diff --git a/api/prisma/migrations/43_add_parking_fee_property/migration.sql b/api/prisma/migrations/43_add_parking_fee_property/migration.sql new file mode 100644 index 0000000000..42503fc972 --- /dev/null +++ b/api/prisma/migrations/43_add_parking_fee_property/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "listings" ADD COLUMN "parking_fee" TEXT; diff --git a/api/prisma/schema.prisma b/api/prisma/schema.prisma index 0c0e8fa4ed..c32f5bcccd 100644 --- a/api/prisma/schema.prisma +++ b/api/prisma/schema.prisma @@ -736,6 +736,7 @@ model Listings { Listings Listings[] @relation("copy_of") lastUpdatedByUserId String? @map("last_updated_by_user_id") @db.Uuid lastUpdatedByUser UserAccounts? @relation("last_updated_by_user", fields: [lastUpdatedByUserId], references: [id], onDelete: NoAction, onUpdate: NoAction) + parkingFee String? @map("parking_fee") @@index([jurisdictionId]) @@map("listings") diff --git a/api/prisma/seed-staging.ts b/api/prisma/seed-staging.ts index 8c76749683..1409c8ba7a 100644 --- a/api/prisma/seed-staging.ts +++ b/api/prisma/seed-staging.ts @@ -61,6 +61,7 @@ export const stagingSeed = async ( FeatureFlagEnum.enableListingPagination, FeatureFlagEnum.enableMarketingStatus, FeatureFlagEnum.enableNeighborhoodAmenities, + FeatureFlagEnum.enableParkingFee, FeatureFlagEnum.enablePartnerDemographics, FeatureFlagEnum.enablePartnerSettings, FeatureFlagEnum.enableSection8Question, @@ -111,6 +112,7 @@ export const stagingSeed = async ( FeatureFlagEnum.enableMarketingStatus, FeatureFlagEnum.enableNeighborhoodAmenities, FeatureFlagEnum.enableNonRegulatedListings, + FeatureFlagEnum.enableParkingFee, FeatureFlagEnum.enablePartnerDemographics, FeatureFlagEnum.enablePartnerSettings, FeatureFlagEnum.enableRegions, @@ -173,6 +175,7 @@ export const stagingSeed = async ( FeatureFlagEnum.enableMarketingStatusMonths, FeatureFlagEnum.enableNeighborhoodAmenities, FeatureFlagEnum.enableNeighborhoodAmenitiesDropdown, + FeatureFlagEnum.enableParkingFee, FeatureFlagEnum.enableProperties, FeatureFlagEnum.enableReferralQuestionUnits, ], diff --git a/api/src/dtos/listings/listing.dto.ts b/api/src/dtos/listings/listing.dto.ts index ba3d9be321..6662a74bba 100644 --- a/api/src/dtos/listings/listing.dto.ts +++ b/api/src/dtos/listings/listing.dto.ts @@ -529,6 +529,14 @@ class Listing extends AbstractDTO { @ApiProperty() name: string; + @Expose() + @ValidateListingPublish('parkingFee', { + groups: [ValidationsGroupsEnum.default], + }) + @IsString({ groups: [ValidationsGroupsEnum.default] }) + @ApiPropertyOptional() + parkingFee?: string; + @Expose() @ValidateListingPublish('postmarkedApplicationsReceivedByDate', { groups: [ValidationsGroupsEnum.default], diff --git a/api/src/enums/feature-flags/feature-flags-enum.ts b/api/src/enums/feature-flags/feature-flags-enum.ts index f27023f0dd..49c4130e49 100644 --- a/api/src/enums/feature-flags/feature-flags-enum.ts +++ b/api/src/enums/feature-flags/feature-flags-enum.ts @@ -33,6 +33,7 @@ export enum FeatureFlagEnum { enableNeighborhoodAmenities = 'enableNeighborhoodAmenities', enableNeighborhoodAmenitiesDropdown = 'enableNeighborhoodAmenitiesDropdown', enableNonRegulatedListings = 'enableNonRegulatedListings', + enableParkingFee = 'enableParkingFee', enablePartnerDemographics = 'enablePartnerDemographics', enablePartnerSettings = 'enablePartnerSettings', enableProperties = 'enableProperties', @@ -210,6 +211,10 @@ export const featureFlagMap: { description: 'When true, non-regulated listings are displayed in listing creation/edit and public listing view', }, + { + name: FeatureFlagEnum.enableParkingFee, + description: 'When true, the parking fee field should be visible', + }, { name: FeatureFlagEnum.enablePartnerDemographics, description: diff --git a/api/src/services/listing-csv-export.service.ts b/api/src/services/listing-csv-export.service.ts index 47c650bb64..7d9586df99 100644 --- a/api/src/services/listing-csv-export.service.ts +++ b/api/src/services/listing-csv-export.service.ts @@ -946,6 +946,18 @@ export class ListingCsvExporterService implements CsvExporterServiceInterface { }); } + if ( + doAnyJurisdictionHaveFeatureFlagSet( + user.jurisdictions, + FeatureFlagEnum.enableParkingFee, + ) + ) { + headers.push({ + path: 'parkingFee', + label: 'Parking Fee', + }); + } + headers.push( ...[ { diff --git a/shared-helpers/src/locales/ar.json b/shared-helpers/src/locales/ar.json index 343dea8a0a..0516d0d114 100644 --- a/shared-helpers/src/locales/ar.json +++ b/shared-helpers/src/locales/ar.json @@ -1135,6 +1135,7 @@ "t.order": "ترتيب", "t.orUpTo": "أو ما يصل إلى", "t.other": "آخر", + "t.parkingFee": "رسوم الإصطفاف", "t.people": "اشخاص", "t.perMonth": "كل شهر", "t.person": "شخص", diff --git a/shared-helpers/src/locales/bn.json b/shared-helpers/src/locales/bn.json index ab04cbf6ea..2032abe934 100644 --- a/shared-helpers/src/locales/bn.json +++ b/shared-helpers/src/locales/bn.json @@ -1135,6 +1135,7 @@ "t.order": "আদেশ", "t.orUpTo": "বা পর্যন্ত", "t.other": "অন্যান্য", + "t.parkingFee": "পার্কিং ফি", "t.people": "মানুষ", "t.perMonth": "প্রতি মাসে", "t.person": "ব্যক্তি", diff --git a/shared-helpers/src/locales/es.json b/shared-helpers/src/locales/es.json index adb79d7a24..d2c0b021b0 100644 --- a/shared-helpers/src/locales/es.json +++ b/shared-helpers/src/locales/es.json @@ -1135,6 +1135,7 @@ "t.order": "Orden", "t.orUpTo": "o hasta", "t.other": "Otro", + "t.parkingFee": "Tarifa de estacionamiento", "t.people": "personas", "t.perMonth": "al mes", "t.person": "persona", diff --git a/shared-helpers/src/locales/general.json b/shared-helpers/src/locales/general.json index 786c8a3a57..389afc34e0 100644 --- a/shared-helpers/src/locales/general.json +++ b/shared-helpers/src/locales/general.json @@ -1132,6 +1132,7 @@ "t.order": "Order", "t.orUpTo": "or up to", "t.other": "Other", + "t.parkingFee": "Parking Fee", "t.people": "people", "t.perMonth": "per month", "t.person": "person", diff --git a/shared-helpers/src/locales/tl.json b/shared-helpers/src/locales/tl.json index 449c128816..a0d7d105be 100644 --- a/shared-helpers/src/locales/tl.json +++ b/shared-helpers/src/locales/tl.json @@ -1135,6 +1135,7 @@ "t.order": "Umorder", "t.orUpTo": "o hanggang sa", "t.other": "Iba pa", + "t.parkingFee": "Bayad sa Paradahan", "t.people": "mga tao", "t.perMonth": "kada buwan", "t.person": "tao", diff --git a/shared-helpers/src/locales/vi.json b/shared-helpers/src/locales/vi.json index da6646fd47..3f5c21f1c0 100644 --- a/shared-helpers/src/locales/vi.json +++ b/shared-helpers/src/locales/vi.json @@ -1135,6 +1135,7 @@ "t.order": "Đặt hàng", "t.orUpTo": "hoặc lên đến", "t.other": "Khác", + "t.parkingFee": "Phí đỗ xe", "t.people": "người", "t.perMonth": "mỗi tháng", "t.person": "người", diff --git a/shared-helpers/src/locales/zh.json b/shared-helpers/src/locales/zh.json index ea0a7f2167..5cfbe57d09 100644 --- a/shared-helpers/src/locales/zh.json +++ b/shared-helpers/src/locales/zh.json @@ -1135,6 +1135,7 @@ "t.order": "命令", "t.orUpTo": "或最多", "t.other": "其他", + "t.parkingFee": "停車費", "t.people": "人", "t.perMonth": "每月", "t.person": "人", diff --git a/shared-helpers/src/types/backend-swagger.ts b/shared-helpers/src/types/backend-swagger.ts index de89dfbf3d..5a800bcf56 100644 --- a/shared-helpers/src/types/backend-swagger.ts +++ b/shared-helpers/src/types/backend-swagger.ts @@ -4273,6 +4273,9 @@ export interface Listing { /** */ name: string + /** */ + parkingFee?: string + /** */ postmarkedApplicationsReceivedByDate?: Date @@ -4987,6 +4990,9 @@ export interface ListingCreate { /** */ name: string + /** */ + parkingFee?: string + /** */ postmarkedApplicationsReceivedByDate?: Date @@ -5345,6 +5351,9 @@ export interface ListingUpdate { /** */ name: string + /** */ + parkingFee?: string + /** */ postmarkedApplicationsReceivedByDate?: Date @@ -8045,6 +8054,7 @@ export enum FeatureFlagEnum { "enableNeighborhoodAmenities" = "enableNeighborhoodAmenities", "enableNeighborhoodAmenitiesDropdown" = "enableNeighborhoodAmenitiesDropdown", "enableNonRegulatedListings" = "enableNonRegulatedListings", + "enableParkingFee" = "enableParkingFee", "enablePartnerDemographics" = "enablePartnerDemographics", "enablePartnerSettings" = "enablePartnerSettings", "enableProperties" = "enableProperties", diff --git a/sites/partners/__tests__/components/listings/PaperListingForm/index.test.tsx b/sites/partners/__tests__/components/listings/PaperListingForm/index.test.tsx index ef7cc35b48..3ca3c5d568 100644 --- a/sites/partners/__tests__/components/listings/PaperListingForm/index.test.tsx +++ b/sites/partners/__tests__/components/listings/PaperListingForm/index.test.tsx @@ -365,6 +365,8 @@ describe("add listing", () => { return true case FeatureFlagEnum.enableHomeType: return true + case FeatureFlagEnum.enableParkingFee: + return true case FeatureFlagEnum.enableCompanyWebsite: return true default: @@ -402,6 +404,7 @@ describe("add listing", () => { "Additional accessibility", "Unit amenities", "Smoking policy", + "Parking fee", "Pets policy", "Services offered", "Credit history", diff --git a/sites/partners/__tests__/pages/listings/[id]/index.test.tsx b/sites/partners/__tests__/pages/listings/[id]/index.test.tsx index c6e8136045..4510782d3b 100644 --- a/sites/partners/__tests__/pages/listings/[id]/index.test.tsx +++ b/sites/partners/__tests__/pages/listings/[id]/index.test.tsx @@ -835,6 +835,7 @@ describe("listing data", () => { ) ).toBeInTheDocument() expect(screen.getByText("Services offered")).toBeInTheDocument() + expect(screen.getByText("Services offered")).toBeInTheDocument() expect(screen.getByText("Professional Help")).toBeInTheDocument() }) diff --git a/sites/partners/page_content/locale_overrides/general.json b/sites/partners/page_content/locale_overrides/general.json index ed8aa5bec7..240ea471ef 100644 --- a/sites/partners/page_content/locale_overrides/general.json +++ b/sites/partners/page_content/locale_overrides/general.json @@ -431,6 +431,7 @@ "listings.sections.neighborhoodAmenitiesSubtitle": "Provide details about any local amenities including grocery stores, health services and parks within 2 miles of your listing.", "listings.sections.neighborhoodAmenitiesSubtitleAlt": "Please provide details about any nearby amenities.", "listings.sections.openHouse": "Open house", + "listings.sections.parkingFeeText": "Parking fee", "listings.sections.photo.helperTextBase": "Select JPEG or PNG file to upload. Please upload horizontal images only at approximately 1440px.", "listings.sections.photo.helperTextLimit": "Up to 10 uploaded images allowed.", "listings.sections.photo.helperTextLimits": "At least %{smart_count} image is required, and up to 10 images are allowed. |||| At least %{smart_count} images are required, and up to 10 images are allowed.", diff --git a/sites/partners/src/components/listings/PaperListingDetails/sections/DetailBuildingFeatures.tsx b/sites/partners/src/components/listings/PaperListingDetails/sections/DetailBuildingFeatures.tsx index cf7615b58c..c7aa76f8f0 100644 --- a/sites/partners/src/components/listings/PaperListingDetails/sections/DetailBuildingFeatures.tsx +++ b/sites/partners/src/components/listings/PaperListingDetails/sections/DetailBuildingFeatures.tsx @@ -30,6 +30,10 @@ const DetailBuildingFeatures = () => { FeatureFlagEnum.enableAccessibilityFeatures, listing.jurisdictions.id ) + const enableParkingFee = doJurisdictionsHaveFeatureFlagOn( + FeatureFlagEnum.enableParkingFee, + listing?.jurisdictions?.id + ) return ( @@ -90,6 +94,15 @@ const DetailBuildingFeatures = () => { )} + {enableParkingFee && ( + + + + {getDetailFieldString(listing.parkingFee)} + + + + )} ) } diff --git a/sites/partners/src/components/listings/PaperListingForm/sections/BuildingFeatures.tsx b/sites/partners/src/components/listings/PaperListingForm/sections/BuildingFeatures.tsx index bb88d8fb9a..45a59ab23f 100644 --- a/sites/partners/src/components/listings/PaperListingForm/sections/BuildingFeatures.tsx +++ b/sites/partners/src/components/listings/PaperListingForm/sections/BuildingFeatures.tsx @@ -1,12 +1,16 @@ -import React, { useMemo, useEffect } from "react" +import React, { useMemo, useEffect, useContext } from "react" import { useFormContext } from "react-hook-form" -import { t, Textarea, FieldGroup } from "@bloom-housing/ui-components" +import { t, Textarea, FieldGroup, Field } from "@bloom-housing/ui-components" import { Grid } from "@bloom-housing/ui-seeds" -import { listingFeatures } from "@bloom-housing/shared-helpers" -import { ListingFeatures } from "@bloom-housing/shared-helpers/src/types/backend-swagger" +import { AuthContext, listingFeatures } from "@bloom-housing/shared-helpers" +import { + FeatureFlagEnum, + ListingFeatures, +} from "@bloom-housing/shared-helpers/src/types/backend-swagger" import SectionWithGrid from "../../../shared/SectionWithGrid" import { defaultFieldProps } from "../../../../lib/helpers" import styles from "../ListingForm.module.scss" +import { ListingContext } from "../../ListingContext" type BuildingFeaturesProps = { enableAccessibilityFeatures?: boolean @@ -16,6 +20,8 @@ type BuildingFeaturesProps = { const BuildingFeatures = (props: BuildingFeaturesProps) => { const formMethods = useFormContext() + const listing = useContext(ListingContext) + const { doJurisdictionsHaveFeatureFlagOn } = useContext(AuthContext) // eslint-disable-next-line @typescript-eslint/unbound-method const { register, setValue, errors, clearErrors } = formMethods @@ -36,6 +42,11 @@ const BuildingFeatures = (props: BuildingFeaturesProps) => { } }, [props.enableAccessibilityFeatures, setValue]) + const enableParkingFee = doJurisdictionsHaveFeatureFlagOn( + FeatureFlagEnum.enableParkingFee, + listing?.jurisdictions?.id + ) + return ( <>
@@ -139,6 +150,24 @@ const BuildingFeatures = (props: BuildingFeaturesProps) => { /> + {enableParkingFee && ( + + + + + + )} {!props.enableAccessibilityFeatures ? null : ( flag.name === "enableAccessibilityFeatures" && flag.active