Skip to content

Commit

Permalink
feat: backend changes for what to expect changes (#508)
Browse files Browse the repository at this point in the history
* fix: update email confirmation what to expect copy

* fix: email tests (bloom-housing#3095)

* feat: new listing type field

* 3032/new what to expect core (bloom-housing#3087)

* feat: bring over What to Expect and update Markdown styles

* feat: show dedicated content on the What to Expect form step

* feat: add additional text to terms and confirmation

* feat: update form conditionals to use waitlist enum

* fix: remove stray import

* fix: typos and improved switch statements

* fix: confirmation text and remove lottery date

* fix: add back in eligibility translations (bloom-housing#3134)

* fix: add back in detail page changes (#510)

* fix: remove check for whatToExpect in cypress test

Co-authored-by: Emily Jablonski <[email protected]>
Co-authored-by: Jared White <[email protected]>
  • Loading branch information
3 people authored Oct 17, 2022
1 parent 9a1a33a commit 85cb4da
Show file tree
Hide file tree
Showing 36 changed files with 556 additions and 219 deletions.
5 changes: 2 additions & 3 deletions backend/core/src/email/email.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ const translationServiceMock = {
readHowYouCanPrepare: "Read about how you can prepare for next steps",
needToMakeUpdates: "Need to make updates?",
ifYouNeedToUpdateInformation: "",

shouldBeChosen:
"Should your application be chosen, be prepared to fill out a more detailed application and provide required supporting documents.",
subject: "Your Application Confirmation",
Expand Down Expand Up @@ -259,7 +258,7 @@ describe("EmailService", () => {
expect(emailMock.html).toMatch("Your Confirmation Number")
expect(emailMock.html).toMatch("Marisela Baca")
expect(emailMock.html).toMatch(
/If you are contacted for an interview, you will need to fill out a more detailed application and provide supporting documents./
/Eligible applicants will be contacted on a first come first serve basis until vacancies are filled./
)
expect(emailMock.html).toMatch(/http:\/\/localhost:3000\/listing\/Uvbk5qurpB2WI9V6WnNdH/)
// contains application id
Expand All @@ -279,7 +278,7 @@ describe("EmailService", () => {

const emailMock = sendMock.mock.calls[0][0]
expect(emailMock.html).toMatch(
/Eligible applicants will be placed in order <strong>based on preference and lottery rank<\/strong>./
/Once the application period closes, eligible applicants will be placed in order based on lottery rank order./
)
})

Expand Down
31 changes: 21 additions & 10 deletions backend/core/src/email/email.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ export class EmailService {
public async confirmation(listing: Listing, application: Application, appUrl: string) {
const jurisdiction = await this.getListingJurisdiction(listing)
void (await this.loadTranslations(jurisdiction, application.language || Language.en))
let eligibleApplicantsText
const listingUrl = `${appUrl}/listing/${listing.id}`
const compiledTemplate = this.template("confirmation")

Expand All @@ -142,22 +141,31 @@ export class EmailService {
)
}

let eligibleText
let preferenceText
let contactText = null
if (listing.reviewOrderType === ListingReviewOrder.firstComeFirstServe) {
eligibleText = this.polyglot.t("confirmation.eligible.fcfs")
preferenceText = this.polyglot.t("confirmation.eligible.fcfsPreference")
}
if (listing.reviewOrderType === ListingReviewOrder.lottery) {
eligibleApplicantsText = new Handlebars.SafeString(
this.polyglot.t("confirmation.eligibleApplicants.lottery")
)
} else {
// for when listing.reviewOrderType === ListingReviewOrder.firstComeFirstServe
eligibleApplicantsText = new Handlebars.SafeString(
this.polyglot.t("confirmation.eligibleApplicants.FCFS")
)
eligibleText = this.polyglot.t("confirmation.eligible.lottery")
preferenceText = this.polyglot.t("confirmation.eligible.lotteryPreference")
}
if (listing.reviewOrderType === ListingReviewOrder.waitlist) {
eligibleText = this.polyglot.t("confirmation.eligible.waitlist")
contactText = this.polyglot.t("confirmation.eligible.waitlistContact")
preferenceText = this.polyglot.t("confirmation.eligible.waitlistPreference")
}

const user = {
firstName: application.applicant.firstName,
middleName: application.applicant.middleName,
lastName: application.applicant.lastName,
}

const nextStepsUrl = this.polyglot.t("confirmation.nextStepsUrl")

await this.send(
application.applicant.emailAddress,
jurisdiction.emailFromAddress,
Expand All @@ -171,7 +179,10 @@ export class EmailService {
listing,
listingUrl,
application,
eligibleApplicantsText,
preferenceText,
interviewText: this.polyglot.t("confirmation.interview"),
eligibleText,
contactText,
nextStepsUrl: nextStepsUrl != "confirmation.nextStepsUrl" ? nextStepsUrl : null,
user,
})
Expand Down
6 changes: 0 additions & 6 deletions backend/core/src/listings/dto/listing-published-create.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { OmitType } from "@nestjs/swagger"
import { UnitCreateDto } from "../../units/dto/unit-create.dto"
import { EnforceLowerCase } from "../../shared/decorators/enforceLowerCase.decorator"
import { ListingImageUpdateDto } from "./listing-image-update.dto"
import { ListingAvailability } from "../types/listing-availability-enum"

export class ListingPublishedCreateDto extends OmitType(ListingCreateDto, [
"assets",
Expand All @@ -39,7 +38,6 @@ export class ListingPublishedCreateDto extends OmitType(ListingCreateDto, [
"rentalAssistance",
"reviewOrderType",
"units",
"listingAvailability",
] as const) {
@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true })
Expand Down Expand Up @@ -77,10 +75,6 @@ export class ListingPublishedCreateDto extends OmitType(ListingCreateDto, [
@Type(() => ListingImageUpdateDto)
images: ListingImageUpdateDto[]

@Expose()
@IsEnum(ListingAvailability, { groups: [ValidationsGroupsEnum.default] })
listingAvailability: ListingAvailability | null

@Expose()
@IsEmail({}, { groups: [ValidationsGroupsEnum.default] })
@EnforceLowerCase()
Expand Down
6 changes: 0 additions & 6 deletions backend/core/src/listings/dto/listing-published-update.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { AssetUpdateDto } from "../../assets/dto/asset.dto"
import { UnitUpdateDto } from "../../units/dto/unit-update.dto"
import { EnforceLowerCase } from "../../shared/decorators/enforceLowerCase.decorator"
import { ListingImageUpdateDto } from "./listing-image-update.dto"
import { ListingAvailability } from "../types/listing-availability-enum"

export class ListingPublishedUpdateDto extends OmitType(ListingUpdateDto, [
"assets",
Expand All @@ -39,7 +38,6 @@ export class ListingPublishedUpdateDto extends OmitType(ListingUpdateDto, [
"rentalAssistance",
"reviewOrderType",
"units",
"listingAvailability",
] as const) {
@Expose()
@ValidateNested({ groups: [ValidationsGroupsEnum.default], each: true })
Expand Down Expand Up @@ -77,10 +75,6 @@ export class ListingPublishedUpdateDto extends OmitType(ListingUpdateDto, [
@Type(() => ListingImageUpdateDto)
images: ListingImageUpdateDto[]

@Expose()
@IsEnum(ListingAvailability, { groups: [ValidationsGroupsEnum.default] })
listingAvailability: ListingAvailability | null

@Expose()
@IsEmail({}, { groups: [ValidationsGroupsEnum.default] })
@EnforceLowerCase()
Expand Down
11 changes: 0 additions & 11 deletions backend/core/src/listings/entities/listing.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ import { ApplicationMethod } from "../../application-methods/entities/applicatio
import { UnitsSummarized } from "../../units/types/units-summarized"
import { UnitsSummary } from "../../units-summary/entities/units-summary.entity"
import { ListingReviewOrder } from "../types/listing-review-order-enum"
import { ListingAvailability } from "../types/listing-availability-enum"
import { ApplicationMethodDto } from "../../application-methods/dto/application-method.dto"
import { ApplicationMethodType } from "../../application-methods/types/application-method-type-enum"
import { ListingFeatures } from "./listing-features.entity"
Expand Down Expand Up @@ -520,16 +519,6 @@ class Listing extends BaseEntity {
})
reviewOrderType?: ListingReviewOrder | null

@Column({ type: "enum", enum: ListingAvailability, nullable: true })
@Expose()
@IsOptional({ groups: [ValidationsGroupsEnum.default] })
@IsEnum(ListingAvailability, { groups: [ValidationsGroupsEnum.default] })
@ApiProperty({
enum: ListingAvailability,
enumName: "ListingAvailability",
})
listingAvailability?: ListingAvailability | null

@Expose()
applicationConfig?: Record<string, unknown>

Expand Down
6 changes: 2 additions & 4 deletions backend/core/src/listings/listings.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Interval } from "@nestjs/schedule"
import { Listing } from "./entities/listing.entity"
import { getView } from "./views/view"
import { summarizeUnits, summarizeUnitsByTypeAndRent } from "../shared/units-transformations"
import { Language, ListingAvailability } from "../../types"
import { Language, ListingReviewOrder } from "../../types"
import { AmiChart } from "../ami-charts/entities/ami-chart.entity"
import { ListingCreateDto } from "./dto/listing-create.dto"
import { ListingUpdateDto } from "./dto/listing-update.dto"
Expand Down Expand Up @@ -111,9 +111,7 @@ export class ListingsService {
await this.authorizeUserActionForListingId(this.req.user, listing.id, authzActions.update)

const availableUnits =
listingDto.listingAvailability === ListingAvailability.availableUnits
? listingDto.units.length
: 0
listingDto.reviewOrderType !== ListingReviewOrder.waitlist ? listingDto.units.length : 0
listingDto.units.forEach((unit) => {
if (!unit.id) {
delete unit.id
Expand Down
4 changes: 0 additions & 4 deletions backend/core/src/listings/types/listing-availability-enum.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum ListingReviewOrder {
lottery = "lottery",
firstComeFirstServe = "firstComeFirstServe",
waitlist = "waitlist",
}
1 change: 0 additions & 1 deletion backend/core/src/listings/views/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ const views: Views = {
"listingImagesImage.id",
"listingImagesImage.fileId",
"listingImagesImage.label",
"listings.listingAvailability",
"utilities.id",
"utilities.water",
"utilities.gas",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { MigrationInterface, QueryRunner } from "typeorm"
import { Language } from "../shared/types/language-enum"

export class newConfirmationEmailTranslations1663104141106 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
let generalTranslation = await queryRunner.query(
`SELECT translations FROM translations WHERE jurisdiction_id IS NULL AND language = ($1)`,
[Language.en]
)

generalTranslation = generalTranslation["0"]["translations"]

generalTranslation.confirmation = {
...generalTranslation.confirmation,
eligible: {
fcfs:
"Eligibile applicants will be contacted on a first come first serve basis until vacancies are filled.",
fcfsPreference:
"Housing preferences, if applicable, will affect first come first serve order.",
lottery:
"Once the application period closes, eligible applicants will be placed in order based on lottery rank order.",
lotteryPreference: "Housing preferences, if applicable, will affect lottery rank order.",
waitlist:
"Eligibile applicants will be placed on the waitlist on a first come first serve basis until waitlist spots are filled.",
waitlistPreference: "Housing preferences, if applicable, will affect waitlist order.",
waitlistContact:
"You may be contacted while on the waitlist to confirm that you wish to remain on the waitlist.",
},
interview:
"If you are contacted for an interview, you will be asked to fill out a more detailed application and provide supporting documents.",
}

await queryRunner.query(
`UPDATE "translations" SET translations = ($1) where jurisdiction_id IS NULL and language = ($2)`,
[generalTranslation, Language.en]
)
}

public async down(queryRunner: QueryRunner): Promise<void> {}
}
61 changes: 61 additions & 0 deletions backend/core/src/migration/1663959354563-new-listing-type-enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { MigrationInterface, QueryRunner } from "typeorm"

export class newListingTypeEnum1663959354563 implements MigrationInterface {
name = "newListingTypeEnum1663959354563"

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TYPE "public"."listings_review_order_type_enum" RENAME TO "listings_review_order_type_enum_old"`
)
await queryRunner.query(
`CREATE TYPE "public"."listings_review_order_type_enum" AS ENUM('lottery', 'firstComeFirstServe', 'waitlist')`
)
await queryRunner.query(
`ALTER TABLE "listings" ALTER COLUMN "review_order_type" TYPE "public"."listings_review_order_type_enum" USING "review_order_type"::"text"::"public"."listings_review_order_type_enum"`
)
await queryRunner.query(`DROP TYPE "public"."listings_review_order_type_enum_old"`)

const listings = await queryRunner.query(`SELECT id, listing_availability FROM listings`)

for (const l of listings) {
if (l.listing_availability === "openWaitlist") {
await queryRunner.query(`UPDATE listings SET review_order_type = ($1) WHERE id = ($2)`, [
"waitlist",
l.id,
])
}
}
await queryRunner.query(`ALTER TABLE "listings" DROP COLUMN "listing_availability"`)
await queryRunner.query(`DROP TYPE "public"."listings_listing_availability_enum"`)
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "listings" ADD "listing_availability" "public"."listings_listing_availability_enum"`
)
await queryRunner.query(
`CREATE TYPE "public"."listings_listing_availability_enum" AS ENUM('availableUnits', 'openWaitlist')`
)
const listings = await queryRunner.query(`SELECT id, review_order_type FROM listings`)

for (const l of listings) {
if (l.review_order_type === "waitlist") {
await queryRunner.query(`UPDATE listings SET listing_availability = ($1) WHERE id = ($2)`, [
"openWaitlist",
l.id,
])
}
}

await queryRunner.query(
`CREATE TYPE "public"."listings_review_order_type_enum_old" AS ENUM('lottery', 'firstComeFirstServe')`
)
await queryRunner.query(
`ALTER TABLE "listings" ALTER COLUMN "review_order_type" TYPE "public"."listings_review_order_type_enum_old" USING "review_order_type"::"text"::"public"."listings_review_order_type_enum_old"`
)
await queryRunner.query(`DROP TYPE "public"."listings_review_order_type_enum"`)
await queryRunner.query(
`ALTER TYPE "public"."listings_review_order_type_enum_old" RENAME TO "listings_review_order_type_enum"`
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { MigrationInterface, QueryRunner } from "typeorm"
import { Language } from "../shared/types/language-enum"

export class emailResetTranslations1665528174645 implements MigrationInterface {
name = "emailResetTranslations1665528174645"

public async up(queryRunner: QueryRunner): Promise<void> {
let generalTranslation = await queryRunner.query(
`SELECT translations FROM translations WHERE jurisdiction_id IS NULL AND language = ($1)`,
[Language.en]
)

generalTranslation = generalTranslation["0"]["translations"]

generalTranslation.confirmation = {
...generalTranslation.confirmation,
eligible: {
fcfs:
"Eligible applicants will be contacted on a first come first serve basis until vacancies are filled.",
waitlist:
"Eligible applicants will be placed on the waitlist on a first come first serve basis until waitlist spots are filled.",
lottery:
"Once the application period closes, eligible applicants will be placed in order based on lottery rank order.",
fcfsPreference:
"Housing preferences, if applicable, will affect first come first serve order.",
waitlistContact:
"You may be contacted while on the waitlist to confirm that you wish to remain on the waitlist.",
lotteryPreference: "Housing preferences, if applicable, will affect lottery rank order.",
waitlistPreference: "Housing preferences, if applicable, will affect waitlist order.",
},
}

await queryRunner.query(
`UPDATE "translations" SET translations = ($1) where jurisdiction_id IS NULL and language = ($2)`,
[generalTranslation, Language.en]
)
}

public async down(queryRunner: QueryRunner): Promise<void> {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { ListingReviewOrder } from "../../../listings/types/listing-review-order
import { ListingStatus } from "../../../listings/types/listing-status-enum"
import { UnitCreateDto } from "../../../units/dto/unit-create.dto"
import { Listing } from "../../../listings/entities/listing.entity"
import { ListingAvailability } from "../../../listings/types/listing-availability-enum"

const coliseumListing: ListingSeedType = {
jurisdictionName: "Alameda",
Expand Down Expand Up @@ -106,8 +105,7 @@ const coliseumListing: ListingSeedType = {
waitlistMaxSize: 3000,
waitlistOpenSpots: 3000,
isWaitlistOpen: true,
whatToExpect: "Custom what to expect text",
listingAvailability: ListingAvailability.availableUnits,
whatToExpect: null,
utilities: {
water: false,
gas: false,
Expand Down
2 changes: 0 additions & 2 deletions backend/core/src/seeder/seeds/listings/listing-triton-seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { ListingReviewOrder } from "../../../listings/types/listing-review-order
import { ListingStatus } from "../../../listings/types/listing-status-enum"
import { UnitCreateDto } from "../../../units/dto/unit-create.dto"
import { Listing } from "../../../listings/entities/listing.entity"
import { ListingAvailability } from "../../../listings/types/listing-availability-enum"
import { classToClass } from "class-transformer"
import dayjs from "dayjs"

Expand Down Expand Up @@ -96,7 +95,6 @@ const tritonListing: ListingSeedType = {
waitlistOpenSpots: 200,
isWaitlistOpen: true,
whatToExpect: null,
listingAvailability: ListingAvailability.availableUnits,
utilities: {
water: true,
gas: true,
Expand Down
3 changes: 1 addition & 2 deletions backend/core/src/seeder/seeds/listings/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { UserCreateDto } from "../../../auth/dto/user-create.dto"
import { CountyCode } from "../../../shared/types/county-code"
import { ListingReviewOrder } from "../../../listings/types/listing-review-order-enum"
import { ListingStatus } from "../../../listings/types/listing-status-enum"
import { ListingAvailability } from "../../../listings/types/listing-availability-enum"
import { ApplicationSection } from "../../../multiselect-question/types/multiselect-application-section-enum"
export const getDate = (days: number) => {
const someDate = new Date()
Expand Down Expand Up @@ -219,7 +218,7 @@ export const defaultListing: ListingSeedType = {
waitlistOpenSpots: null,
isWaitlistOpen: false,
waitlistMaxSize: null,
listingAvailability: ListingAvailability.availableUnits,
whatToExpect: "Custom what to expect text",
}

// Preferences
Expand Down
Loading

0 comments on commit 85cb4da

Please sign in to comment.