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
400 changes: 205 additions & 195 deletions api/src/services/external-listing.service.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion api/src/services/listing.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,7 @@ export class ListingService implements OnModuleInit {
result = await this.translationService.translateListing(result, lang);
}

if (result.unitGroups.length > 0) {
if (result.unitGroups?.length > 0) {
addUnitGroupsSummarized(result);
} else {
await this.addUnitsSummarized(result);
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@
"listings.apply.applicationSeason": "يجب على السكان التقديم في",
"listings.apply.applicationWillBeAvailableOn": "سيكون التطبيق متاحًا للتنزيل والاستلام في %{openDate}",
"listings.apply.applyOnline": "تقديم الطلب عبر الإنترنت",
"listings.apply.applyOnlineMessage": "* ينقلك هذا الزر إلى موقع إلكتروني خارجي، حيث يمكنك إنشاء حساب والتقدم بطلب لهذا الإعلان.",
"listings.apply.downloadApplication": "تنزيل التطبيق",
"listings.apply.dropOffApplication": "طلب الاستلام",
"listings.apply.dropOffApplicationOrMail": "تسليم الطلب أو إرساله عبر البريد الأمريكي",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/bn.json
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@
"listings.apply.applicationSeason": "বাসিন্দাদের আবেদন করতে হবে",
"listings.apply.applicationWillBeAvailableOn": "%{openDate} এ ডাউনলোড এবং পিক -আপের জন্য আবেদন পাওয়া যাবে",
"listings.apply.applyOnline": "অনলাইনে আবেদন করুন",
"listings.apply.applyOnlineMessage": "* এই বোতামটি আপনাকে একটি বাহ্যিক ওয়েবসাইটে নিয়ে যাবে, যেখানে আপনি একটি অ্যাকাউন্ট তৈরি করে এই তালিকাভুক্তির জন্য আবেদন করতে পারবেন।",
"listings.apply.downloadApplication": "অ্যাপ্লিকেশন ডাউনলোড করুন",
"listings.apply.dropOffApplication": "আবেদনপত্র জমা দিন",
"listings.apply.dropOffApplicationOrMail": "আবেদনপত্র জমা দিন অথবা মার্কিন ডাকযোগে পাঠান",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@
"listings.apply.applicationSeason": "Los residentes deben aplicar en",
"listings.apply.applicationWillBeAvailableOn": "La solicitud podrá ser descargada y recogida el %{openDate}",
"listings.apply.applyOnline": "Haga su solicitud por internet",
"listings.apply.applyOnlineMessage": "*Este botón te lleva a un sitio web externo donde puedes crear una cuenta y solicitar este listado.",
"listings.apply.downloadApplication": "Descargar la solicitud",
"listings.apply.dropOffApplication": "Lleve la solicitud",
"listings.apply.dropOffApplicationOrMail": "Lleve la solicitud o envíela por correo a través del Servicio Postal de los EE.UU.",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/fa.json
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@
"listings.apply.applicationSeason": "ساکنین باید درخواست دهند",
"listings.apply.applicationWillBeAvailableOn": "برنامه برای دانلود و دریافت در %{openDate} در دسترس خواهد بود.",
"listings.apply.applyOnline": "درخواست آنلاین",
"listings.apply.applyOnlineMessage": "* این دکمه شما را به یک وب‌سایت خارجی هدایت می‌کند که در آن می‌توانید یک حساب کاربری ایجاد کنید و برای این آگهی درخواست دهید.",
"listings.apply.downloadApplication": "دانلود اپلیکیشن",
"listings.apply.dropOffApplication": "درخواست ترخیص",
"listings.apply.dropOffApplicationOrMail": "درخواست را تحویل دهید یا از طریق پست ایالات متحده ارسال کنید",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/general.json
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,7 @@
"listings.apply.applicationSeason": "Residents should apply in",
"listings.apply.applicationWillBeAvailableOn": "Application will be available for download and pick up on %{openDate}",
"listings.apply.applyOnline": "Apply online",
"listings.apply.applyOnlineMessage": "* This button brings you to an external website where you can create an account and apply for this listing.",
Comment thread
mcgarrye marked this conversation as resolved.
"listings.apply.downloadApplication": "Download application",
"listings.apply.dropOffApplication": "Drop off application",
"listings.apply.dropOffApplicationOrMail": "Drop off application or send by US Mail",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/hy.json
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@
"listings.apply.applicationSeason": "Բնակիչները պետք է դիմեն",
"listings.apply.applicationWillBeAvailableOn": "Դիմումը հասանելի կլինի ներբեռնման և վերցման համար %{openDate}-ին։",
"listings.apply.applyOnline": "Դիմել առցանց",
"listings.apply.applyOnlineMessage": "* Այս կոճակը ձեզ կտանի արտաքին կայք, որտեղ կարող եք ստեղծել հաշիվ և դիմել այս ցուցակի համար։",
"listings.apply.downloadApplication": "Ներբեռնել ծրագիրը",
"listings.apply.dropOffApplication": "Դիմումի ներկայացում",
"listings.apply.dropOffApplicationOrMail": "Դիմումը թողեք կամ ուղարկեք ԱՄՆ փոստով",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@
"listings.apply.applicationSeason": "주민들은 다음 주소로 신청해야 합니다.",
"listings.apply.applicationWillBeAvailableOn": "신청서는 %{openDate}부터 다운로드 및 수령 가능합니다.",
"listings.apply.applyOnline": "온라인으로 지원하세요",
"listings.apply.applyOnlineMessage": "* 이 버튼을 누르면 계정을 생성하고 해당 공고에 지원할 수 있는 외부 웹사이트로 이동합니다.",
"listings.apply.downloadApplication": "애플리케이션 다운로드",
"listings.apply.dropOffApplication": "신청서 제출",
"listings.apply.dropOffApplicationOrMail": "신청서를 직접 제출하거나 우편으로 보내주세요.",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/tl.json
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@
"listings.apply.applicationSeason": "Dapat mag-apply ang mga residente sa",
"listings.apply.applicationWillBeAvailableOn": "Magiging available ang application para i-download at kunin sa %{openDate}",
"listings.apply.applyOnline": "Mag-apply online",
"listings.apply.applyOnlineMessage": "* Dinadala ka ng button na ito sa isang panlabas na website kung saan maaari kang lumikha ng isang account at mag-apply para sa listahang ito.",
"listings.apply.downloadApplication": "I-download ang application",
"listings.apply.dropOffApplication": "I-drop off ang application",
"listings.apply.dropOffApplicationOrMail": "Ihulog ang application o ipadala sa US Mail",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@
"listings.apply.applicationSeason": "Cư dân nên nộp đơn tại",
"listings.apply.applicationWillBeAvailableOn": "Đơn ghi danh sẽ có sẵn để tải xuống và tới nhận vào %{openDate}",
"listings.apply.applyOnline": "Nộp đơn trực tuyến",
"listings.apply.applyOnlineMessage": "* Nút này sẽ đưa bạn đến một trang web bên ngoài nơi bạn có thể tạo tài khoản và đăng ký danh sách này.",
"listings.apply.downloadApplication": "Tải ứng dụng",
"listings.apply.dropOffApplication": "Nộp đơn",
"listings.apply.dropOffApplicationOrMail": "Nộp đơn hoặc gửi qua Bưu điện Hoa Kỳ",
Expand Down
1 change: 1 addition & 0 deletions shared-helpers/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@
"listings.apply.applicationSeason": "居民应申请",
"listings.apply.applicationWillBeAvailableOn": "申請表將可供下載,亦可在 %{openDate} 領取",
"listings.apply.applyOnline": "在线申请",
"listings.apply.applyOnlineMessage": "* 此按钮将带您进入外部网站,您可以在其中创建帐户并申请此列表。",
"listings.apply.downloadApplication": "下载应用程序",
"listings.apply.dropOffApplication": "投递申请",
"listings.apply.dropOffApplicationOrMail": "投递申请或通过美国邮政寄送",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,21 @@ describe("ListingViewSeedsHelpers", () => {
expect(result.isCommonApp).toBe(true)
})

it("should return online application URL from Internal method with external URL", () => {
const methods: ApplicationMethod[] = [
{
type: ApplicationMethodsTypeEnum.Internal,
externalReference: "",
} as ApplicationMethod,
]

const result = getOnlineApplicationURL(methods, "123", false, "www.externalURL.com")
expect(result.url).toBe(
"www.externalURL.com/applications/start/choose-language?listingId=123"
)
expect(result.isCommonApp).toBe(true)
})

it("should include preview parameter when preview is true", () => {
const methods: ApplicationMethod[] = [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,45 @@ describe("<Apply>", () => {
expect(screen.queryByText("Download application")).not.toBeInTheDocument()
})

it("shows apply online button for internal online application for external listing", () => {
render(
<Apply
listing={{
...listing,
applicationDueDate: dayjs(new Date()).add(5, "days").toDate(),
applicationMethods: [
{
id: "id",
createdAt: new Date(),
updatedAt: new Date(),
type: ApplicationMethodsTypeEnum.Internal,
acceptsPostmarkedApplications: null,
externalReference: null,
paperApplications: [],
phoneNumber: null,
},
],
externalURL: "www.externalURL.com",
}}
preview={false}
setShowDownloadModal={() => null}
/>
)
expect(screen.getByRole("heading", { level: 2, name: "How to apply" })).toBeInTheDocument()
expect(screen.getByText("Apply online")).toBeInTheDocument()
expect(
screen.getByText(
"* This button brings you to an external website where you can create an account and apply for this listing."
)
).toBeInTheDocument()
expect(screen.getByRole("link", { name: "Apply online" })).toHaveAttribute(
"href",
`www.externalURL.com/applications/start/choose-language?listingId=${listing.id}`
)

expect(screen.queryByText("Download application")).not.toBeInTheDocument()
})

it("shows redirected apply online button for internal online application with mandated accounts on while signed out", () => {
process.env.showMandatedAccounts = "TRUE"
render(
Expand Down
7 changes: 7 additions & 0 deletions sites/public/src/components/listing/GetApplication.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@ export interface ApplicationsProps {
listingStatus?: string
/** Whether or not to block submission of test application */
preview?: boolean
/** Whether or not to show apply online helper text */
isExternal?: boolean
strings?: {
applicationsOpenInFuture?: string
applyOnline?: string
applyOnlineMessage?: string
downloadApplication?: string
getAPaperApplication?: string
getDirections?: string
Expand Down Expand Up @@ -105,6 +108,10 @@ const GetApplication = (props: ApplicationsProps) => {
{props.strings?.applyOnline ?? t("listings.apply.applyOnline")}
</Button>
)}
<div className="text-gray-800 text-sm">
{props.isExternal &&
(props.strings?.applyOnlineMessage ?? t("listings.apply.applyOnlineMessage"))}
</div>
</div>
Comment thread
mcgarrye marked this conversation as resolved.
)}

Expand Down
8 changes: 5 additions & 3 deletions sites/public/src/components/listing/ListingView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ interface ListingProps {
}

const getUnhiddenMultiselectQuestions = (
arrayToSeach: ListingMultiselectQuestion[],
arrayToSearch: ListingMultiselectQuestion[],
section: MultiselectQuestionsApplicationSectionEnum
): ListingMultiselectQuestion[] => {
return arrayToSeach.filter(
return arrayToSearch.filter(
(elem) =>
elem.multiselectQuestions.applicationSection === section &&
!elem.multiselectQuestions.hideFromListing
Expand Down Expand Up @@ -376,7 +376,7 @@ export const ListingView = (props: ListingProps) => {
let onlineApplicationURL
let isCommonApp = false
if (hasMethod(listing.applicationMethods, ApplicationMethodsTypeEnum.Internal)) {
onlineApplicationURL = `/applications/start/choose-language?listingId=${listing.id}`
onlineApplicationURL = `${listing.externalURL}/applications/start/choose-language?listingId=${listing.id}`
onlineApplicationURL += `${props.preview ? "&preview=true" : ""}`
isCommonApp = true
} else if (hasMethod(listing.applicationMethods, ApplicationMethodsTypeEnum.ExternalLink)) {
Expand Down Expand Up @@ -435,6 +435,7 @@ export const ListingView = (props: ListingProps) => {
initialStateLoaded &&
!profile &&
onlineApplicationURLInfo.isCommonApp &&
!listing.externalURL &&
//previewing applications should not require admin to login
!props.preview

Expand Down Expand Up @@ -462,6 +463,7 @@ export const ListingView = (props: ListingProps) => {
listingName={listing.name}
listingId={listing.id}
listingStatus={listing.status}
isExternal={!listing.externalURL}
/>
{listing.status !== ListingsStatusEnum.closed && submissionAddressExists && (
<SubmitApplication
Expand Down
2 changes: 1 addition & 1 deletion sites/public/src/components/listing/ListingViewSeeds.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export const ListingViewSeeds = ({ listing, jurisdiction, profile, preview }: Li
/>
{isFeatureFlagOn(jurisdiction, FeatureFlagEnum.enableNonRegulatedListings) &&
listing.listingType === EnumListingListingType.nonRegulated && (
<OtherFeatures hasEbllClearence={listing.hasHudEbllClearance} />
<OtherFeatures hasEbllClearance={listing.hasHudEbllClearance} />
)}
</>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,15 @@ export const getPaperApplications = (applicationMethods: ApplicationMethod[]) =>
export const getOnlineApplicationURL = (
applicationMethods: ApplicationMethod[],
listingId: string,
preview: boolean
preview: boolean,
externalURL = ""
) => {
let onlineApplicationURL
let isCommonApp = false
if (hasMethod(applicationMethods, ApplicationMethodsTypeEnum.Internal)) {
onlineApplicationURL = `/applications/start/choose-language?listingId=${listingId}`
onlineApplicationURL = `${
externalURL ? externalURL : ""
}/applications/start/choose-language?listingId=${listingId}`
onlineApplicationURL += `${preview ? "&preview=true" : ""}`
isCommonApp = true
} else if (hasMethod(applicationMethods, ApplicationMethodsTypeEnum.ExternalLink)) {
Expand Down
12 changes: 9 additions & 3 deletions sites/public/src/components/listing/listing_sections/Apply.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,19 @@ export const Apply = ({ listing, preview, setShowDownloadModal }: ApplyProps) =>
const { initialStateLoaded, profile } = useContext(AuthContext)

const applicationsClosed = dayjs() > dayjs(listing.applicationDueDate)

const onlineApplicationURLInfo = getOnlineApplicationURL(
listing.applicationMethods,
listing.id,
preview
preview,
listing.externalURL
)

const redirectIfLogInRequired = () =>
process.env.showMandatedAccounts &&
initialStateLoaded &&
!profile &&
onlineApplicationURLInfo.isCommonApp &&
!listing.externalURL &&
//previewing applications should not require admin to login
!preview

Expand Down Expand Up @@ -148,7 +149,12 @@ export const Apply = ({ listing, preview, setShowDownloadModal }: ApplyProps) =>
{t("listings.apply.howToApply")}
</Heading>
{hasPrimaryApplicationMethod && (
<>{onlineApplicationUrl ? ApplyOnlineButton : DownloadApplicationButton}</>
<>
{onlineApplicationUrl ? ApplyOnlineButton : DownloadApplicationButton}
<div className={"seeds-m-bs-content"}>
{listing.externalURL && t("listings.apply.applyOnlineMessage")}
</div>
</>
)}
</Card.Section>
{showSecondarySection && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ import styles from "../ListingViewSeeds.module.scss"
import { t } from "@bloom-housing/ui-components"

type OtherFeaturesProps = {
hasEbllClearence: boolean
hasEbllClearance: boolean
}

export const OtherFeatures = ({ hasEbllClearence }: OtherFeaturesProps) => {
export const OtherFeatures = ({ hasEbllClearance }: OtherFeaturesProps) => {
return (
<div className="seeds-m-bs-header">
<HeadingGroup
heading={t("t.other")}
headingProps={{ size: "lg", priority: 3 }}
subheading={
hasEbllClearence ? t("listings.hasEbllClearance") : t("listings.noEbllClearance")
hasEbllClearance ? t("listings.hasEbllClearance") : t("listings.noEbllClearance")
}
className={`${styles["heading-group"]} seeds-m-be-section`}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ const ApplicationChooseLanguage = () => {
}
}, [listing, router, toastyRef])

const imageUrl = listing?.assets
const imageUrl = listing?.listingImages
? imageUrlFromListing(listing, parseInt(process.env.listingPhotoSize))[0]
: ""

Expand Down
17 changes: 10 additions & 7 deletions sites/public/src/pages/listing/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ export async function getServerSideProps(context: { params: Record<string, strin
let response

try {
response = await axios.get(`${process.env.backendApiBase}/listings/${context.params.id}`, {
headers: {
passkey: process.env.API_PASS_KEY,
"x-forwarded-for":
context.req.headers["x-forwarded-for"] ?? context.req.socket.remoteAddress,
},
})
response = await axios.get(
`${process.env.backendApiBase}/listings/${context.params.id}?view=address`,
{
headers: {
passkey: process.env.API_PASS_KEY,
"x-forwarded-for":
context.req.headers["x-forwarded-for"] ?? context.req.socket.remoteAddress,
},
}
)
} catch (e) {
return { notFound: true }
}
Expand Down
18 changes: 16 additions & 2 deletions sites/public/src/pages/listing/[id]/[slug].tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useContext } from "react"
import { GetStaticPaths, GetStaticProps } from "next"
import { useRouter } from "next/router"
import axios from "axios"
import axios, { AxiosResponse } from "axios"
import { t } from "@bloom-housing/ui-components"
import {
imageUrlFromListing,
Expand Down Expand Up @@ -99,7 +99,7 @@ export const getStaticProps: GetStaticProps = async (context: {
params: Record<string, string>
locale: string
}) => {
let response
let response: AxiosResponse
try {
response = await axios.get(`${process.env.backendApiBase}/listings/${context.params.id}`, {
headers: {
Expand All @@ -112,6 +112,20 @@ export const getStaticProps: GetStaticProps = async (context: {
}
const jurisdiction = fetchJurisdictionByName()

if (response.data.externalURL) {
try {
response = await axios.get(
`${response.data.externalURL}/listings/external/${response.data.externalListingId}`,
{ headers: { language: context.locale } }
)
// re-setting the externalURL field with the publicUrl if we need to redirect to the external site
response.data.externalURL = response.data.jurisdiction.publicUrl
} catch (e) {
console.error(`Error fetching external listing data: ${e}`)
return { notFound: true }
}
}

return {
props: { listing: response.data, jurisdiction: await jurisdiction },
revalidate: Number(process.env.cacheRevalidate),
Expand Down
Loading