Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions api/prisma/seed-staging/seed-bridge-bay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import dayjs from 'dayjs';
import { SpokenLanguageEnum } from '../../src/enums/applications/spoken-language-enum';
import { HouseholdMemberRelationship } from '../../src/enums/applications/household-member-relationship-enum';
import { FeatureFlagEnum } from '../../src/enums/feature-flags/feature-flags-enum';
import { amiChartFactory } from '../seed-helpers/ami-chart-factory';
import { randomBoolean } from '../seed-helpers/boolean-generator';
import { jurisdictionFactory } from '../seed-helpers/jurisdiction-factory';
import { multiselectQuestionFactory } from '../seed-helpers/multiselect-question-factory';
Expand Down Expand Up @@ -1505,12 +1506,12 @@ export const realisticAddressesForActive = [
county: 'San Flor',
},
{
street: '1120A Madera Avenue, Menlo Park, CA 94025',
street: '1120A Madera Avenue',
city: 'Menlo Park',
state: 'CA',
zipCode: '94025',
latitude: 36.961738,
longitude: -120.064487,
latitude: 37.47197516388515,
longitude: -122.15722059781827,
Comment thread
ludtkemorgan marked this conversation as resolved.
county: 'San Flor',
},
{
Expand Down Expand Up @@ -2609,6 +2610,15 @@ export const createBridgeBayJurisdictions = async (
});
otherJurisdictions.push(createdSubJurisdiction);

const amiChart = await prismaClient.amiChart.create({
data: amiChartFactory(
10,
createdSubJurisdiction.id,
null,
createdSubJurisdiction.name,
),
});

const msqData = msqV2
? {
applicationSection:
Expand Down Expand Up @@ -2665,7 +2675,12 @@ export const createBridgeBayJurisdictions = async (
};
});

await seedListings(prismaClient, createdSubJurisdiction.id, listings);
await seedListings(
prismaClient,
createdSubJurisdiction.id,
listings,
amiChart,
);
}

// Add some listings with pending and closed status to the top level jurisdiction
Expand Down
6 changes: 5 additions & 1 deletion api/src/services/listing.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,12 @@ selectViews.map = {
select: {
monthlyRent: true,
unitTypes: {
select: { numBedrooms: true, name: true },
select: {
numBedrooms: true,
name: true,
},
},
accessibilityPriorityType: true,
},
},
};
Expand Down
1 change: 1 addition & 0 deletions api/test/unit/services/listing.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1581,6 +1581,7 @@ describe('Testing listing service', () => {
unitTypes: {
select: { numBedrooms: true, name: true },
},
accessibilityPriorityType: true,
},
},
},
Expand Down
6 changes: 3 additions & 3 deletions shared-helpers/src/utilities/Address.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ interface AddressProps {
getDirections?: boolean
}

export const oneLineAddress = (address: AddressType) => {
export const oneLineAddress = (address: AddressType, displayCounty = false) => {
if (!address) return ""
return `${address.street}${address.street2 ? `, ${address.street2}` : ""}, ${address.city}, ${
address.state
} ${address.zipCode}`
displayCounty && address.county ? `${address.county}, ` : ""
}${address.state} ${address.zipCode}`
}

export const multiLineAddress = (address: AddressType) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
} from "@bloom-housing/shared-helpers/src/types/backend-swagger"
import { AuthContext, MessageContext } from "@bloom-housing/shared-helpers"
import UnitForm from "../UnitForm"
import { useAmiChartList, useJurisdiction, useUnitTypeList } from "../../../../lib/hooks"
import { useAmiChartList, useUnitTypeList } from "../../../../lib/hooks"
import { useFormContext, useWatch } from "react-hook-form"
import { TempUnit, TempUnitGroup } from "../../../../lib/listings/formTypes"
import { defaultFieldProps, fieldHasError, fieldMessage, getLabel } from "../../../../lib/helpers"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe("<ListingCard>", () => {
}}
/>
)
const tags = getListingTags(listing, true)
const tags = getListingTags(listing, { hideReviewTags: true })
expect(view.getByText(listing.name)).toBeDefined()
expect(view.getByText("98 Archer Street, San Jose, CA 95112")).toBeDefined()
tags.forEach((tag) => {
Expand Down
137 changes: 137 additions & 0 deletions sites/public/__tests__/components/browse/map/ListingsList.test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from "react"
import { render, screen } from "@testing-library/react"
import { t } from "@bloom-housing/ui-components"
import { FeatureFlagEnum } from "@bloom-housing/shared-helpers/src/types/backend-swagger"
import { ListingsList } from "../../../../src/components/browse/map/ListingsList"
import { useListingsMapContext } from "../../../../src/components/browse/map/ListingsMapContext"
import { getMapListings } from "../../../../src/lib/helpers"

const paginationMock = jest.fn()
const tIfExistsMock = jest.fn()

// These mocks enable us to just test the branching logic in ListingsList without worrying about the internal implementation of the children, which are tested separately
jest.mock("../../../../src/components/browse/map/ListingsMapContext", () => ({
Expand All @@ -25,11 +27,25 @@ jest.mock("../../../../src/components/browse/map/Pagination", () => ({
},
}))

jest.mock("@bloom-housing/shared-helpers", () => ({
tIfExists: (key: string) => tIfExistsMock(key),
BloomCard: ({ title, children }) => (
<div data-testid="bloom-card">
<div data-testid="bloom-card-title">{title}</div>
{children}
</div>
),
}))

jest.mock("@bloom-housing/ui-components", () => {
const actual = jest.requireActual("@bloom-housing/ui-components")

return {
...actual,
t: (key: string) => {
const result = tIfExistsMock(key)
return result !== null && result !== undefined ? result : actual.t(key)
},
LoadingOverlay: ({ isLoading, children }) => (
<div data-testid="loading-overlay" data-loading={String(isLoading)}>
{children}
Expand Down Expand Up @@ -61,6 +77,7 @@ describe("ListingsList", () => {
beforeEach(() => {
jest.clearAllMocks()
delete process.env.notificationsSignUpUrl
tIfExistsMock.mockReturnValue(null)
;(useListingsMapContext as jest.Mock).mockReturnValue(baseContext)
})

Expand Down Expand Up @@ -129,4 +146,124 @@ describe("ListingsList", () => {

expect(screen.queryByRole("navigation", { name: "Listings list pagination" })).toBeNull()
})

describe("info cards", () => {
it("shows notifications card when notificationsSignUpUrl is set", () => {
;(useListingsMapContext as jest.Mock).mockReturnValue({
...baseContext,
notificationsSignUpUrl: "https://example.com/sign-up",
})

render(<ListingsList />)

expect(screen.getByTestId("bloom-card-title")).toHaveTextContent(t("welcome.signUp"))
expect(screen.getByRole("link", { name: t("welcome.signUpToday") })).toHaveAttribute(
"href",
"https://example.com/sign-up"
)
})

it("links notifications card to /account/notifications when enableCustomListingNotifications flag is on", () => {
;(useListingsMapContext as jest.Mock).mockReturnValue({
...baseContext,
activeFeatureFlags: [FeatureFlagEnum.enableCustomListingNotifications],
})

render(<ListingsList />)

expect(screen.getByRole("link", { name: t("welcome.signUpToday") })).toHaveAttribute(
"href",
"/account/notifications"
)
})

it("shows resources card when enableResources flag is on", () => {
;(useListingsMapContext as jest.Mock).mockReturnValue({
...baseContext,
activeFeatureFlags: [FeatureFlagEnum.enableResources],
})

render(<ListingsList />)

expect(screen.getByTestId("bloom-card-title")).toHaveTextContent(
t("welcome.seeMoreOpportunitiesTruncated")
)
expect(
screen.getByRole("link", { name: t("welcome.viewAdditionalHousingTruncated") })
).toHaveAttribute("href", "/additional-resources")
})

it("shows additional resources card when enableAdditionalResources flag is on", () => {
;(useListingsMapContext as jest.Mock).mockReturnValue({
...baseContext,
activeFeatureFlags: [FeatureFlagEnum.enableAdditionalResources],
})

tIfExistsMock.mockImplementation((key: string) => {
const translations: Record<string, string> = {
"resources.additionalResourcesTitle": "Get more information about the Accessible Housing",
"resources.additionalResourcesLink": "https://example.com/additional-resources",
}
return translations[key] ?? null
})

render(<ListingsList />)

expect(screen.getByTestId("bloom-card-title")).toHaveTextContent(
t("resources.additionalResourcesTitle")
)
expect(screen.getByRole("link", { name: t("welcome.learnMore") })).toHaveAttribute(
"href",
t("resources.additionalResourcesLink")
)
})

it("shows no info cards when no flags or url are set", () => {
render(<ListingsList />)

expect(screen.queryByTestId("bloom-card")).not.toBeInTheDocument()
})

it("renders dynamic additional cards from locale translations", () => {
tIfExistsMock.mockImplementation((key: string) => {
const translations: Record<string, string> = {
"listingResource.additionalCard1.title": "Looking for housing elsewhere?",
"listingResource.additionalCard1.link": "https://example.com",
"listingResource.additionalCard1.linkLabel": "See Listings",
}
return translations[key] ?? null
})

render(<ListingsList />)

expect(screen.getByTestId("bloom-card-title")).toHaveTextContent(
"Looking for housing elsewhere?"
)
expect(screen.getByRole("link", { name: "See Listings" })).toHaveAttribute(
"href",
"https://example.com"
)
})

it("renders multiple dynamic additional cards when multiple locale keys exist", () => {
tIfExistsMock.mockImplementation((key: string) => {
const translations: Record<string, string> = {
"listingResource.additionalCard1.title": "Card One Title",
"listingResource.additionalCard1.link": "https://example.com/one",
"listingResource.additionalCard1.linkLabel": "Go to One",
"listingResource.additionalCard2.title": "Card Two Title",
"listingResource.additionalCard2.link": "https://example.com/two",
"listingResource.additionalCard2.linkLabel": "Go to Two",
}
return translations[key] ?? null
})

render(<ListingsList />)

const cards = screen.getAllByTestId("bloom-card-title")
expect(cards).toHaveLength(2)
expect(cards[0]).toHaveTextContent("Card One Title")
expect(cards[1]).toHaveTextContent("Card Two Title")
})
})
})
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import React from "react"
import { fireEvent, render, screen } from "@testing-library/react"
import { MapListingCard } from "../../../../src/components/browse/map/MapListingCard"
import {
ListingsMapContext,
ListingsMapContextValue,
} from "../../../../src/components/browse/map/ListingsMapContext"
import {
getListingStackedGroupTableData,
getListingStackedTableData,
Expand Down Expand Up @@ -34,15 +38,39 @@ jest.mock("../../../../src/components/listing/listing_sections/MainDetails", ()
}))

describe("MapListingCard", () => {
const jurisdiction = { id: "jurisdiction-1", featureFlags: [] } as any
const mockContextValue: ListingsMapContextValue = {
bedrooms: [],
bathrooms: [],
jurisdictions: [],
multiselectData: [],
searchResults: { listings: [], markers: [], currentPage: 1, lastPage: 1, totalItems: 0 },
listView: false,
setListView: jest.fn(),
isDesktop: true,
isLoading: false,
setIsLoading: jest.fn(),
visibleMarkers: [],
setVisibleMarkers: jest.fn(),
isFirstBoundsLoad: true,
setIsFirstBoundsLoad: jest.fn(),
setFilterDrawerOpen: jest.fn(),
filterCount: 0,
onPageChange: jest.fn(),
infoWindowIndex: null,
setInfoWindowIndex: jest.fn(),
activeFeatureFlags: [],
}

const renderWithContext = (ui: React.ReactElement) =>
render(<ListingsMapContext.Provider value={mockContextValue}>{ui}</ListingsMapContext.Provider>)

beforeEach(() => {
jest.clearAllMocks()
;(isFeatureFlagOn as jest.Mock).mockReturnValue(false)
})

it("renders core listing content and uses units summarized table data", () => {
render(<MapListingCard listing={listing} index={0} jurisdiction={jurisdiction} />)
renderWithContext(<MapListingCard listing={listing} index={0} />)

expect(screen.getByRole("heading", { name: listing.name })).toBeInTheDocument()
expect(screen.getByText("123 Test Street")).toBeInTheDocument()
Expand All @@ -53,14 +81,8 @@ describe("MapListingCard", () => {

it("renders close button in force mobile view and triggers onClose", () => {
const onClose = jest.fn()
render(
<MapListingCard
listing={listing}
index={0}
jurisdiction={jurisdiction}
forceMobileView={true}
onClose={onClose}
/>
renderWithContext(
<MapListingCard listing={listing} index={0} forceMobileView={true} onClose={onClose} />
)

fireEvent.click(screen.getByRole("button", { name: /close/i }))
Expand All @@ -75,7 +97,7 @@ describe("MapListingCard", () => {
unitGroups: [],
}

render(<MapListingCard listing={listingWithoutUnits} index={0} jurisdiction={jurisdiction} />)
renderWithContext(<MapListingCard listing={listingWithoutUnits} index={0} />)

expect(screen.queryByRole("table")).not.toBeInTheDocument()
expect(getListingStackedTableData).not.toHaveBeenCalled()
Expand Down
4 changes: 4 additions & 0 deletions sites/public/page_content/locale_overrides/general.json
Comment thread
ludtkemorgan marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
"footer.forGeneralQuestions": "For general program inquiries, you may call us at 000-000-0000.",
"listings.additionalFeesDisclaimer": "Fees are not charged for reasonable accommodations needed due to disability, such as emotional support animals. Fees are also not charged for aids and services needed for effective communication due to a disability. With respect to credit checks, applicants receiving government rent subsidies have the option to provide \"lawful, verifiable alternative evidence\" of their ability to pay rent, instead of relying on their credit history.",
"listings.petPolicyDescription": "Service dogs and emotional support animals are not pets and are permitted as required by law. Pets may also be required to be allowed in certain types of housing, such as publicly financed housing developments.",
"listingResource.additionalCard1.title": "Looking for housing elsewhere?",
"listingResource.additionalCard1.link": "https://www.exygy.com",
"listingResource.additionalCard1.linkLabel": "See listings",
"listingResource.additionalCard1.subtext": "See available affordable housing listings in other areas.",
"pageDescription.faq": "Find answers to common questions about affordable housing in Bloomington.",
"region.name": "Bloomington",
"resources.contactDescription": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
Expand Down
1 change: 0 additions & 1 deletion sites/public/src/components/browse/FilterDrawerHelpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
EnumListingFilterParamsComparison,
FilterAvailabilityEnum,
HomeTypeEnum,
IdDTO,
ListingFeatures,
ListingFeaturesConfiguration,
ListingFilterKeys,
Expand Down
Loading
Loading