@bloom-housing/ui-components 4.2.2-alpha.21 → 4.2.2-alpha.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/index.ts +11 -10
- package/package.json +3 -3
- package/src/global/text.scss +2 -2
- package/src/headers/Heading.tsx +1 -0
- package/src/helpers/MultiLineAddress.tsx +37 -0
- package/src/helpers/OneLineAddress.tsx +21 -0
- package/src/page_components/listing/ListingMap.tsx +8 -3
- package/src/page_components/listing/listing_sidebar/Contact.tsx +110 -0
- package/src/page_components/listing/listing_sidebar/ContactAddress.tsx +41 -0
- package/src/page_components/listing/listing_sidebar/GetApplication.tsx +35 -15
- package/src/page_components/listing/listing_sidebar/QuantityRowSection.tsx +46 -0
- package/src/page_components/listing/listing_sidebar/SubmitApplication.tsx +52 -57
- package/src/page_components/listing/listing_sidebar/events/EventSection.tsx +3 -2
- package/src/page_components/sign-in/ResendConfirmationModal.tsx +1 -3
- package/src/helpers/address.tsx +0 -47
- package/src/page_components/listing/listing_sidebar/LeasingAgent.tsx +0 -72
- package/src/page_components/listing/listing_sidebar/SidebarAddress.tsx +0 -56
- package/src/page_components/listing/listing_sidebar/Waitlist.tsx +0 -49
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,49 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [4.2.2-alpha.24](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.2.2-alpha.23...@bloom-housing/ui-components@4.2.2-alpha.24) (2022-05-04)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Code Refactoring
|
|
10
|
+
|
|
11
|
+
* remove backend dependencies from sidebar application components ([#2675](https://github.com/bloom-housing/bloom/issues/2675)) ([d2ebf87](https://github.com/bloom-housing/bloom/commit/d2ebf87c34af3f5b6168fa4e08663fea0a4a872c))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### BREAKING CHANGES
|
|
15
|
+
|
|
16
|
+
* the LeasingAgent component has been renamed to Contact with a new generalized prop set, the SidebarAddress component has been renamed to ContactAddress with a new generalized prop set
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
## [4.2.2-alpha.23](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.2.2-alpha.22...@bloom-housing/ui-components@4.2.2-alpha.23) (2022-05-04)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Code Refactoring
|
|
26
|
+
|
|
27
|
+
* remove business logic, strings from waitlist component ([#2689](https://github.com/bloom-housing/bloom/issues/2689)) ([a5721db](https://github.com/bloom-housing/bloom/commit/a5721db518453ddbd777e50ca92fdeac19997aa9))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### BREAKING CHANGES
|
|
31
|
+
|
|
32
|
+
* the Waitlist component was renamed to QuantityRowSection which also has a new prop set to account for a flexible number of rows and strings
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
## [4.2.2-alpha.22](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.2.2-alpha.21...@bloom-housing/ui-components@4.2.2-alpha.22) (2022-05-03)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Features
|
|
42
|
+
|
|
43
|
+
* **backend:** improve ami chart dto definitions ([#2677](https://github.com/bloom-housing/bloom/issues/2677)) ([ca3890e](https://github.com/bloom-housing/bloom/commit/ca3890e2759f230824e31e6bd985300f40b0a0ed))
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
6
49
|
## [4.2.2-alpha.21](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.2.2-alpha.20...@bloom-housing/ui-components@4.2.2-alpha.21) (2022-04-29)
|
|
7
50
|
|
|
8
51
|
**Note:** Version bump only for package @bloom-housing/ui-components
|
package/index.ts
CHANGED
|
@@ -52,23 +52,24 @@ export * from "./src/headers/SiteHeader"
|
|
|
52
52
|
export * from "./src/headers/Heading"
|
|
53
53
|
|
|
54
54
|
/* Helpers */
|
|
55
|
-
export * from "./src/helpers/address"
|
|
56
55
|
export * from "./src/helpers/capitalize"
|
|
57
56
|
export * from "./src/helpers/dateToString"
|
|
57
|
+
export * from "./src/helpers/debounce"
|
|
58
58
|
export * from "./src/helpers/formOptions"
|
|
59
|
+
export * from "./src/helpers/formatYesNoLabel"
|
|
60
|
+
export * from "./src/helpers/getTranslationWithArguments"
|
|
59
61
|
export * from "./src/helpers/links"
|
|
60
62
|
export * from "./src/helpers/mergeDeep"
|
|
63
|
+
export * from "./src/helpers/MultiLineAddress"
|
|
61
64
|
export * from "./src/helpers/numberOrdinal"
|
|
62
|
-
export * from "./src/helpers/
|
|
63
|
-
export * from "./src/helpers/debounce"
|
|
64
|
-
export * from "./src/helpers/validators"
|
|
65
|
-
export * from "./src/helpers/formatYesNoLabel"
|
|
66
|
-
export * from "./src/helpers/getTranslationWithArguments"
|
|
65
|
+
export * from "./src/helpers/OneLineAddress"
|
|
67
66
|
export * from "./src/helpers/preferences"
|
|
68
67
|
export * from "./src/helpers/resolveObject"
|
|
68
|
+
export * from "./src/helpers/tableSummaries"
|
|
69
|
+
export * from "./src/helpers/translator"
|
|
69
70
|
export * from "./src/helpers/useIntersect"
|
|
70
71
|
export * from "./src/helpers/useMutate"
|
|
71
|
-
export * from "./src/helpers/
|
|
72
|
+
export * from "./src/helpers/validators"
|
|
72
73
|
|
|
73
74
|
/* Icons */
|
|
74
75
|
export * from "./src/icons/HeaderBadge"
|
|
@@ -108,14 +109,14 @@ export * from "./src/page_components/listing/ListingMap"
|
|
|
108
109
|
export * from "./src/page_components/listing/ListingsGroup"
|
|
109
110
|
export * from "./src/page_components/listing/UnitTables"
|
|
110
111
|
export * from "./src/page_components/listing/listing_sidebar/GetApplication"
|
|
111
|
-
export * from "./src/page_components/listing/listing_sidebar/
|
|
112
|
+
export * from "./src/page_components/listing/listing_sidebar/Contact"
|
|
112
113
|
export * from "./src/page_components/listing/listing_sidebar/ListingUpdated"
|
|
113
114
|
export * from "./src/page_components/listing/listing_sidebar/NumberedHeader"
|
|
114
115
|
export * from "./src/page_components/listing/listing_sidebar/OrDivider"
|
|
115
116
|
export * from "./src/page_components/listing/listing_sidebar/ReferralApplication"
|
|
116
|
-
export * from "./src/page_components/listing/listing_sidebar/
|
|
117
|
+
export * from "./src/page_components/listing/listing_sidebar/ContactAddress"
|
|
117
118
|
export * from "./src/page_components/listing/listing_sidebar/SubmitApplication"
|
|
118
|
-
export * from "./src/page_components/listing/listing_sidebar/
|
|
119
|
+
export * from "./src/page_components/listing/listing_sidebar/QuantityRowSection"
|
|
119
120
|
export * from "./src/page_components/listing/listing_sidebar/WhatToExpect"
|
|
120
121
|
export * from "./src/page_components/listing/listing_sidebar/events/DownloadLotteryResults"
|
|
121
122
|
export * from "./src/page_components/listing/listing_sidebar/events/EventSection"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bloom-housing/ui-components",
|
|
3
|
-
"version": "4.2.2-alpha.
|
|
3
|
+
"version": "4.2.2-alpha.24",
|
|
4
4
|
"author": "Sean Albert <sean.albert@exygy.com>",
|
|
5
5
|
"description": "Shared user interface components for Bloom affordable housing system",
|
|
6
6
|
"homepage": "https://github.com/bloom-housing/bloom/tree/master/shared/ui-components",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"webpack": "^4.44.2"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@bloom-housing/backend-core": "^4.2.2-alpha.
|
|
73
|
+
"@bloom-housing/backend-core": "^4.2.2-alpha.7",
|
|
74
74
|
"@mapbox/mapbox-sdk": "^0.13.0",
|
|
75
75
|
"@types/body-scroll-lock": "^2.6.1",
|
|
76
76
|
"@types/jwt-decode": "^2.2.1",
|
|
@@ -102,5 +102,5 @@
|
|
|
102
102
|
"tailwindcss": "2.2.10",
|
|
103
103
|
"typesafe-actions": "^5.1.0"
|
|
104
104
|
},
|
|
105
|
-
"gitHead": "
|
|
105
|
+
"gitHead": "755db7d3f81a90f7d9ece409f4171f87b5096248"
|
|
106
106
|
}
|
package/src/global/text.scss
CHANGED
package/src/headers/Heading.tsx
CHANGED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
export interface Address {
|
|
4
|
+
city?: string
|
|
5
|
+
latitude?: number
|
|
6
|
+
longitude?: number
|
|
7
|
+
placeName?: string
|
|
8
|
+
state?: string
|
|
9
|
+
street2?: string
|
|
10
|
+
street?: string
|
|
11
|
+
zipCode?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface MultiLineAddressProps {
|
|
15
|
+
address: Address
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const MultiLineAddress = ({ address }: MultiLineAddressProps) => {
|
|
19
|
+
if (!address) return null
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
{address.placeName && (
|
|
24
|
+
<>
|
|
25
|
+
{address.placeName}
|
|
26
|
+
<br />
|
|
27
|
+
</>
|
|
28
|
+
)}
|
|
29
|
+
{address.street} {address.street2}
|
|
30
|
+
{(address.street || address.street2) && <br />}
|
|
31
|
+
{address.city}
|
|
32
|
+
{address.city && (address.state || address.zipCode) && ","} {address.state} {address.zipCode}
|
|
33
|
+
</>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { MultiLineAddress as default, MultiLineAddress }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Address } from "./MultiLineAddress"
|
|
3
|
+
|
|
4
|
+
export interface OneLineAddressProps {
|
|
5
|
+
address: Address
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const OneLineAddress = ({ address }: OneLineAddressProps) => {
|
|
9
|
+
if (!address) return null
|
|
10
|
+
|
|
11
|
+
return (
|
|
12
|
+
<>
|
|
13
|
+
{address.street} {address.street2}
|
|
14
|
+
{address.street && `, `}
|
|
15
|
+
{address.city}
|
|
16
|
+
{address.city && (address.state || address.zipCode) && ","} {address.state} {address.zipCode}
|
|
17
|
+
</>
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { OneLineAddress as default, OneLineAddress }
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import React, { useState, useCallback, useEffect
|
|
1
|
+
import React, { useState, useCallback, useEffect } from "react"
|
|
2
2
|
import "mapbox-gl/dist/mapbox-gl.css"
|
|
3
3
|
import MapGL, { Marker } from "react-map-gl"
|
|
4
4
|
|
|
5
5
|
import "./ListingMap.scss"
|
|
6
|
-
import { MultiLineAddress, Address } from "../../helpers/
|
|
6
|
+
import { MultiLineAddress, Address } from "../../helpers/MultiLineAddress"
|
|
7
7
|
import { useIntersect } from "../../.."
|
|
8
|
+
import { Heading } from "../../headers/Heading"
|
|
8
9
|
|
|
9
10
|
export interface ListingMapProps {
|
|
10
11
|
address?: Address
|
|
@@ -107,7 +108,11 @@ const ListingMap = (props: ListingMapProps) => {
|
|
|
107
108
|
return (
|
|
108
109
|
<div className="listing-map" ref={setIntersectingElement}>
|
|
109
110
|
<div className="addressPopup">
|
|
110
|
-
{props.listingName &&
|
|
111
|
+
{props.listingName && (
|
|
112
|
+
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
113
|
+
{props.listingName}
|
|
114
|
+
</Heading>
|
|
115
|
+
)}
|
|
111
116
|
<MultiLineAddress address={props.address} />
|
|
112
117
|
</div>
|
|
113
118
|
{(process.env.mapBoxToken || process.env.MAPBOX_TOKEN) && hasIntersected && (
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { ContactAddress } from "./ContactAddress"
|
|
3
|
+
import { Icon, IconFillColors } from "../../../icons/Icon"
|
|
4
|
+
import { Address } from "../../../helpers/MultiLineAddress"
|
|
5
|
+
import { Heading } from "../../../headers/Heading"
|
|
6
|
+
|
|
7
|
+
export interface ContactProps {
|
|
8
|
+
/** Any number of text sections rendered after the contact information */
|
|
9
|
+
additionalInformation?: { title: string; content: string | React.ReactNode }[]
|
|
10
|
+
/** The contact's address */
|
|
11
|
+
contactAddress?: Address
|
|
12
|
+
/** The contact's company and website */
|
|
13
|
+
contactCompany?: { name: string; website: string }
|
|
14
|
+
/** The contact's email */
|
|
15
|
+
contactEmail?: string
|
|
16
|
+
/** The contact's name */
|
|
17
|
+
contactName?: string
|
|
18
|
+
/** The contact's phone number */
|
|
19
|
+
contactPhoneNumber?: string
|
|
20
|
+
/** Additional information pertaining to the contact's phone number */
|
|
21
|
+
contactPhoneNumberNote?: string
|
|
22
|
+
/** The contact's title */
|
|
23
|
+
contactTitle?: string
|
|
24
|
+
/** The text for the section's header */
|
|
25
|
+
sectionTitle: string
|
|
26
|
+
strings: { email?: string; getDirections: string; website?: string }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Displays information about a contact, including their address, contact information, and notes */
|
|
30
|
+
const Contact = ({
|
|
31
|
+
additionalInformation,
|
|
32
|
+
contactAddress,
|
|
33
|
+
contactCompany,
|
|
34
|
+
contactEmail,
|
|
35
|
+
contactName,
|
|
36
|
+
contactPhoneNumber,
|
|
37
|
+
contactPhoneNumberNote,
|
|
38
|
+
contactTitle,
|
|
39
|
+
sectionTitle,
|
|
40
|
+
strings,
|
|
41
|
+
}: ContactProps) => {
|
|
42
|
+
const formattedPhoneLink = contactPhoneNumber
|
|
43
|
+
? `tel:${contactPhoneNumber.replace(/[-()]/g, "")}`
|
|
44
|
+
: undefined
|
|
45
|
+
const formattedCompanyWebsite =
|
|
46
|
+
contactCompany?.website && !contactCompany?.website.startsWith("http")
|
|
47
|
+
? `http://${contactCompany?.website}`
|
|
48
|
+
: contactCompany?.website
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<section className="aside-block">
|
|
52
|
+
<Heading priority={4} style={"sidebarHeader"}>
|
|
53
|
+
{sectionTitle}
|
|
54
|
+
</Heading>
|
|
55
|
+
|
|
56
|
+
{contactName && <p className="text-xl">{contactName}</p>}
|
|
57
|
+
{contactTitle && <p className="text-gray-700">{contactTitle}</p>}
|
|
58
|
+
{contactCompany?.name && <p className="text-gray-700">{contactCompany.name}</p>}
|
|
59
|
+
|
|
60
|
+
{contactPhoneNumber && (
|
|
61
|
+
<>
|
|
62
|
+
<p className="mt-3">
|
|
63
|
+
<a href={formattedPhoneLink}>
|
|
64
|
+
<Icon symbol="phone" size="medium" fill={IconFillColors.primary} className={"pr-2"} />
|
|
65
|
+
{contactPhoneNumber}
|
|
66
|
+
</a>
|
|
67
|
+
</p>
|
|
68
|
+
{contactPhoneNumberNote && (
|
|
69
|
+
<p className="text-sm text-gray-700">{contactPhoneNumberNote}</p>
|
|
70
|
+
)}
|
|
71
|
+
</>
|
|
72
|
+
)}
|
|
73
|
+
|
|
74
|
+
{contactEmail && (
|
|
75
|
+
<p className="my-3">
|
|
76
|
+
<a href={`mailto:${contactEmail}`}>
|
|
77
|
+
<Icon symbol="mail" size="medium" fill={IconFillColors.primary} className={"pr-2"} />
|
|
78
|
+
{strings?.email && strings?.email}
|
|
79
|
+
</a>
|
|
80
|
+
</p>
|
|
81
|
+
)}
|
|
82
|
+
|
|
83
|
+
{formattedCompanyWebsite && (
|
|
84
|
+
<p className="my-3">
|
|
85
|
+
<a href={formattedCompanyWebsite} target="_blank" rel="noreferrer noopener">
|
|
86
|
+
<Icon symbol="globe" size="medium" fill={IconFillColors.primary} className={"pr-2"} />
|
|
87
|
+
{strings?.website && strings?.website}
|
|
88
|
+
</a>
|
|
89
|
+
</p>
|
|
90
|
+
)}
|
|
91
|
+
|
|
92
|
+
{contactAddress && (
|
|
93
|
+
<ContactAddress address={contactAddress} mapString={strings.getDirections} />
|
|
94
|
+
)}
|
|
95
|
+
|
|
96
|
+
{additionalInformation?.map((info) => {
|
|
97
|
+
return (
|
|
98
|
+
<>
|
|
99
|
+
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
100
|
+
{info.title}
|
|
101
|
+
</Heading>
|
|
102
|
+
<div className="text-gray-800 text-tiny markdown">{info.content}</div>
|
|
103
|
+
</>
|
|
104
|
+
)
|
|
105
|
+
})}
|
|
106
|
+
</section>
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { Contact as default, Contact }
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import ReactDOMServer from "react-dom/server"
|
|
3
|
+
import { Icon, IconFillColors } from "../../../icons/Icon"
|
|
4
|
+
import { MultiLineAddress, Address } from "../../../helpers/MultiLineAddress"
|
|
5
|
+
import { OneLineAddress } from "../../../helpers/OneLineAddress"
|
|
6
|
+
|
|
7
|
+
export interface ContactAddressProps {
|
|
8
|
+
/** An address */
|
|
9
|
+
address: Address
|
|
10
|
+
/** A string for the map link */
|
|
11
|
+
mapString: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Renders an address followed by a Google Maps link to the address */
|
|
15
|
+
const ContactAddress = ({ address, mapString }: ContactAddressProps) => {
|
|
16
|
+
if (!address?.street) return null
|
|
17
|
+
|
|
18
|
+
const oneLineAddress = <OneLineAddress address={address} />
|
|
19
|
+
const mainAddress = <MultiLineAddress address={address} />
|
|
20
|
+
const googleMapsHref =
|
|
21
|
+
"https://www.google.com/maps/place/" + ReactDOMServer.renderToStaticMarkup(oneLineAddress)
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<p className="text-gray-700 mb-1">{mainAddress}</p>
|
|
26
|
+
<p className="mb-4">
|
|
27
|
+
<a
|
|
28
|
+
href={googleMapsHref}
|
|
29
|
+
className="inline-block pt-1"
|
|
30
|
+
target="_blank"
|
|
31
|
+
rel="noreferrer noopener"
|
|
32
|
+
>
|
|
33
|
+
<Icon symbol="map" size="medium" fill={IconFillColors.primary} className={"pr-2"} />
|
|
34
|
+
{mapString}
|
|
35
|
+
</a>
|
|
36
|
+
</p>
|
|
37
|
+
</>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export { ContactAddress as default, ContactAddress }
|
|
@@ -3,10 +3,11 @@ import { t } from "../../../helpers/translator"
|
|
|
3
3
|
import { Button } from "../../../actions/Button"
|
|
4
4
|
import { LinkButton } from "../../../actions/LinkButton"
|
|
5
5
|
import { AppearanceStyleType } from "../../../global/AppearanceTypes"
|
|
6
|
-
import { Address } from "../../../helpers/
|
|
7
|
-
import {
|
|
6
|
+
import { Address } from "../../../helpers/MultiLineAddress"
|
|
7
|
+
import { ContactAddress } from "./ContactAddress"
|
|
8
8
|
import { OrDivider } from "./OrDivider"
|
|
9
|
-
import {
|
|
9
|
+
import { Heading } from "../../../headers/Heading"
|
|
10
|
+
import Markdown from "markdown-to-jsx"
|
|
10
11
|
|
|
11
12
|
export interface PaperApplication {
|
|
12
13
|
fileURL: string
|
|
@@ -14,26 +15,30 @@ export interface PaperApplication {
|
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export interface ApplicationsProps {
|
|
17
|
-
|
|
18
|
+
/** The pickup address for the application */
|
|
19
|
+
applicationPickUpAddress?: Address
|
|
20
|
+
/** Office hours for the agent at the pickup address */
|
|
21
|
+
applicationPickUpAddressOfficeHours?: string
|
|
22
|
+
/** Whether or not applications are currently open */
|
|
18
23
|
applicationsOpen: boolean
|
|
24
|
+
/** The date applications open */
|
|
19
25
|
applicationsOpenDate?: string
|
|
26
|
+
/** The URL for an online applications */
|
|
27
|
+
onlineApplicationURL?: string
|
|
28
|
+
/** Any number of paper application objects, including their URL and language */
|
|
20
29
|
paperApplications?: PaperApplication[]
|
|
30
|
+
/** Whether or not there is a paper application method */
|
|
21
31
|
paperMethod?: boolean
|
|
32
|
+
/** The date mailed applications must be received by */
|
|
22
33
|
postmarkedApplicationsReceivedByDate?: string
|
|
23
|
-
|
|
24
|
-
applicationPickUpAddress?: Address
|
|
34
|
+
/** Whether or not to hide actionable application buttons */
|
|
25
35
|
preview?: boolean
|
|
26
|
-
listingStatus?: ListingStatus
|
|
27
36
|
}
|
|
28
|
-
|
|
37
|
+
/** Displays information regarding how to apply, including an online application link button, paper application downloads, and a paper application pickup address */
|
|
29
38
|
const GetApplication = (props: ApplicationsProps) => {
|
|
30
39
|
const [showDownload, setShowDownload] = useState(false)
|
|
31
40
|
const toggleDownload = () => setShowDownload(!showDownload)
|
|
32
41
|
|
|
33
|
-
if (props.listingStatus === ListingStatus.closed) {
|
|
34
|
-
return null
|
|
35
|
-
}
|
|
36
|
-
|
|
37
42
|
return (
|
|
38
43
|
<section className="aside-block">
|
|
39
44
|
<h2 className="text-caps-underline">{t("listings.apply.howToApply")}</h2>
|
|
@@ -95,11 +100,26 @@ const GetApplication = (props: ApplicationsProps) => {
|
|
|
95
100
|
{props.applicationsOpen && (props.onlineApplicationURL || props.paperMethod) && (
|
|
96
101
|
<OrDivider bgColor="white" />
|
|
97
102
|
)}
|
|
98
|
-
<
|
|
99
|
-
|
|
103
|
+
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
104
|
+
{t("listings.apply.pickUpAnApplication")}
|
|
105
|
+
</Heading>
|
|
106
|
+
<ContactAddress
|
|
100
107
|
address={props.applicationPickUpAddress}
|
|
101
|
-
|
|
108
|
+
mapString={t("t.getDirections")}
|
|
102
109
|
/>
|
|
110
|
+
{props.applicationPickUpAddressOfficeHours && (
|
|
111
|
+
<>
|
|
112
|
+
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
113
|
+
{t("leasingAgent.officeHours")}
|
|
114
|
+
</Heading>
|
|
115
|
+
<p className="text-gray-800 text-tiny markdown">
|
|
116
|
+
<Markdown
|
|
117
|
+
children={props.applicationPickUpAddressOfficeHours}
|
|
118
|
+
options={{ disableParsingRawHTML: true }}
|
|
119
|
+
/>
|
|
120
|
+
</p>
|
|
121
|
+
</>
|
|
122
|
+
)}
|
|
103
123
|
</>
|
|
104
124
|
)}
|
|
105
125
|
</section>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
export interface QuantityRow {
|
|
4
|
+
amount: number | null
|
|
5
|
+
text: string
|
|
6
|
+
emphasized?: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface QuantityRowSectionProps {
|
|
10
|
+
/** Any amount of number/text combinations, rendered in a list */
|
|
11
|
+
quantityRows: QuantityRow[]
|
|
12
|
+
strings: {
|
|
13
|
+
sectionTitle: string
|
|
14
|
+
description?: string | React.ReactNode
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const QuantityRowSection = ({ quantityRows, strings }: QuantityRowSectionProps) => {
|
|
19
|
+
const getRow = (row: QuantityRow) => {
|
|
20
|
+
return (
|
|
21
|
+
<li
|
|
22
|
+
key={row.text}
|
|
23
|
+
className={`uppercase text-gray-800 ${
|
|
24
|
+
row.emphasized ? "font-bold" : "font-normal"
|
|
25
|
+
} font-alt-sans leading-7`}
|
|
26
|
+
>
|
|
27
|
+
<span className="text-right w-12 inline-block pr-2.5 text-base">{row.amount}</span>
|
|
28
|
+
<span className={"text-sm"}>{row.text}</span>
|
|
29
|
+
</li>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<section className="aside-block is-tinted">
|
|
35
|
+
<h4 className="text-caps-tiny">{strings.sectionTitle}</h4>
|
|
36
|
+
<div>
|
|
37
|
+
{strings.description && (
|
|
38
|
+
<p className="text-tiny text-gray-800 pb-3">{strings.description}</p>
|
|
39
|
+
)}
|
|
40
|
+
{quantityRows.length && <ul>{quantityRows.map((row) => getRow(row))}</ul>}
|
|
41
|
+
</div>
|
|
42
|
+
</section>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { QuantityRowSection as default, QuantityRowSection }
|
|
@@ -1,78 +1,73 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
|
-
import
|
|
3
|
-
import { Address } from "../../../helpers/
|
|
4
|
-
import {
|
|
2
|
+
import Markdown from "markdown-to-jsx"
|
|
3
|
+
import { Address } from "../../../helpers/MultiLineAddress"
|
|
4
|
+
import { ContactAddress } from "./ContactAddress"
|
|
5
5
|
import { OrDivider } from "./OrDivider"
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
export interface PostmarkedApplication {
|
|
9
|
-
postmarkedApplicationsReceivedByDate: string | null
|
|
10
|
-
developer: string
|
|
11
|
-
applicationsDueDate: string | null
|
|
12
|
-
}
|
|
6
|
+
import { Heading } from "../../../headers/Heading"
|
|
13
7
|
|
|
14
8
|
export interface ApplicationAddressesProps {
|
|
15
|
-
|
|
9
|
+
/** The dropoff address for paper applications */
|
|
16
10
|
applicationDropOffAddress?: Address
|
|
11
|
+
/** Office hours for developers at the dropoff address for paper applications */
|
|
17
12
|
applicationDropOffAddressOfficeHours?: string
|
|
13
|
+
/** The mailing address for paper applications */
|
|
14
|
+
applicationMailingAddress?: Address
|
|
15
|
+
/** The application organization, often the developer */
|
|
18
16
|
applicationOrganization?: string
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
!(props.applicationMailingAddress || props.applicationDropOffAddress)
|
|
27
|
-
) {
|
|
28
|
-
return null
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const getPostmarkString = () => {
|
|
32
|
-
const applicationDueDate = props.postmarkedApplicationData?.applicationsDueDate
|
|
33
|
-
const postmarkReceivedByDate =
|
|
34
|
-
props.postmarkedApplicationData?.postmarkedApplicationsReceivedByDate
|
|
35
|
-
const developer = props.postmarkedApplicationData?.developer
|
|
36
|
-
if (applicationDueDate) {
|
|
37
|
-
return postmarkReceivedByDate
|
|
38
|
-
? t("listings.apply.submitPaperDueDatePostMark", {
|
|
39
|
-
applicationDueDate,
|
|
40
|
-
postmarkReceivedByDate,
|
|
41
|
-
developer,
|
|
42
|
-
})
|
|
43
|
-
: t("listings.apply.submitPaperDueDateNoPostMark", {
|
|
44
|
-
applicationDueDate,
|
|
45
|
-
developer,
|
|
46
|
-
})
|
|
47
|
-
} else {
|
|
48
|
-
return postmarkReceivedByDate
|
|
49
|
-
? t("listings.apply.submitPaperNoDueDatePostMark", { postmarkReceivedByDate, developer })
|
|
50
|
-
: t("listings.apply.submitPaperNoDueDateNoPostMark", { developer })
|
|
51
|
-
}
|
|
17
|
+
strings: {
|
|
18
|
+
postmark?: string
|
|
19
|
+
mailHeader?: string
|
|
20
|
+
sectionHeader?: string
|
|
21
|
+
dropOffHeader?: string
|
|
22
|
+
officeHoursHeader?: string
|
|
23
|
+
mapString: string
|
|
52
24
|
}
|
|
25
|
+
}
|
|
53
26
|
|
|
27
|
+
/** Displays information regarding paper applications, including two sections: (1) how to mail in applications and (2) how to drop off applications */
|
|
28
|
+
const SubmitApplication = ({
|
|
29
|
+
applicationDropOffAddress,
|
|
30
|
+
applicationDropOffAddressOfficeHours,
|
|
31
|
+
applicationMailingAddress,
|
|
32
|
+
applicationOrganization,
|
|
33
|
+
strings,
|
|
34
|
+
}: ApplicationAddressesProps) => {
|
|
54
35
|
return (
|
|
55
36
|
<>
|
|
56
37
|
<section className="aside-block is-tinted bg-gray-100">
|
|
57
|
-
<div className="text-serif-lg">{
|
|
58
|
-
{
|
|
38
|
+
<div className="text-serif-lg">{strings.sectionHeader}</div>
|
|
39
|
+
{applicationMailingAddress && (
|
|
59
40
|
<>
|
|
60
|
-
<
|
|
41
|
+
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
42
|
+
{strings.mailHeader}
|
|
43
|
+
</Heading>
|
|
61
44
|
<>
|
|
62
|
-
<p className="text-gray-700">{
|
|
63
|
-
<
|
|
45
|
+
<p className="text-gray-700">{applicationOrganization}</p>
|
|
46
|
+
<ContactAddress address={applicationMailingAddress} mapString={strings.mapString} />
|
|
64
47
|
</>
|
|
65
|
-
<p className="mt-4 text-tiny text-gray-750">{
|
|
48
|
+
{strings.postmark && <p className="mt-4 text-tiny text-gray-750">{strings.postmark}</p>}
|
|
66
49
|
</>
|
|
67
50
|
)}
|
|
68
|
-
{
|
|
51
|
+
{applicationDropOffAddress && (
|
|
69
52
|
<>
|
|
70
|
-
{
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
53
|
+
{applicationMailingAddress && <OrDivider bgColor="gray-100" />}
|
|
54
|
+
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
55
|
+
{strings.dropOffHeader}
|
|
56
|
+
</Heading>
|
|
57
|
+
<ContactAddress address={applicationDropOffAddress} mapString={strings.mapString} />
|
|
58
|
+
{applicationDropOffAddressOfficeHours && (
|
|
59
|
+
<>
|
|
60
|
+
<Heading priority={3} style={"sidebarSubHeader"}>
|
|
61
|
+
{strings.officeHoursHeader}
|
|
62
|
+
</Heading>
|
|
63
|
+
<p className="mt-4 text-tiny text-gray-750">
|
|
64
|
+
<Markdown
|
|
65
|
+
children={applicationDropOffAddressOfficeHours}
|
|
66
|
+
options={{ disableParsingRawHTML: true }}
|
|
67
|
+
/>
|
|
68
|
+
</p>
|
|
69
|
+
</>
|
|
70
|
+
)}
|
|
76
71
|
</>
|
|
77
72
|
)}
|
|
78
73
|
</section>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
|
+
import Heading from "../../../../headers/Heading"
|
|
2
3
|
|
|
3
4
|
export type EventType = {
|
|
4
5
|
timeString?: string
|
|
@@ -19,9 +20,9 @@ const EventSection = (props: EventSectionProps) => {
|
|
|
19
20
|
return (
|
|
20
21
|
<section className="aside-block">
|
|
21
22
|
{props.headerText && (
|
|
22
|
-
<
|
|
23
|
+
<Heading priority={4} style={props.sectionHeader ? "sidebarHeader" : "sidebarSubHeader"}>
|
|
23
24
|
{props.headerText}
|
|
24
|
-
</
|
|
25
|
+
</Heading>
|
|
25
26
|
)}
|
|
26
27
|
{props.events.map((event, index) => (
|
|
27
28
|
<div key={`events-${index}`} className={`${index !== props.events.length - 1 && "pb-3"}`}>
|
|
@@ -6,9 +6,8 @@ import {
|
|
|
6
6
|
Form,
|
|
7
7
|
Field,
|
|
8
8
|
emailRegex,
|
|
9
|
-
NavigationContext,
|
|
10
9
|
} from "@bloom-housing/ui-components"
|
|
11
|
-
import React, { useEffect, useMemo
|
|
10
|
+
import React, { useEffect, useMemo } from "react"
|
|
12
11
|
import { useForm } from "react-hook-form"
|
|
13
12
|
|
|
14
13
|
export type ResendConfirmationModalProps = {
|
|
@@ -30,7 +29,6 @@ const ResendConfirmationModal = ({
|
|
|
30
29
|
onClose,
|
|
31
30
|
onSubmit,
|
|
32
31
|
}: ResendConfirmationModalProps) => {
|
|
33
|
-
const { router } = useContext(NavigationContext)
|
|
34
32
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
35
33
|
const { register, errors, reset, getValues, trigger } = useForm({
|
|
36
34
|
defaultValues: useMemo(() => {
|
package/src/helpers/address.tsx
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
|
|
3
|
-
export interface Address {
|
|
4
|
-
city?: string
|
|
5
|
-
latitude?: number
|
|
6
|
-
longitude?: number
|
|
7
|
-
placeName?: string
|
|
8
|
-
state?: string
|
|
9
|
-
street2?: string
|
|
10
|
-
street?: string
|
|
11
|
-
zipCode?: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface AddressProps {
|
|
15
|
-
address: Address
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const OneLineAddress = (props: AddressProps) => {
|
|
19
|
-
if (!props.address) return null
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<>
|
|
23
|
-
{props.address.street},{` `}
|
|
24
|
-
{props.address.city}, {props.address.state} {props.address.zipCode}
|
|
25
|
-
</>
|
|
26
|
-
)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const MultiLineAddress = (props: AddressProps) => {
|
|
30
|
-
if (!props.address) return null
|
|
31
|
-
|
|
32
|
-
return (
|
|
33
|
-
<>
|
|
34
|
-
{props.address.placeName && (
|
|
35
|
-
<>
|
|
36
|
-
{props.address.placeName}
|
|
37
|
-
<br />
|
|
38
|
-
</>
|
|
39
|
-
)}
|
|
40
|
-
{props.address.street} {props.address.street2}
|
|
41
|
-
{(props.address.street || props.address.street2) && <br />}
|
|
42
|
-
{props.address.city}
|
|
43
|
-
{props.address.city && (props.address.state || props.address.zipCode) && ","}{" "}
|
|
44
|
-
{props.address.state} {props.address.zipCode}
|
|
45
|
-
</>
|
|
46
|
-
)
|
|
47
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { SidebarAddress } from "./SidebarAddress"
|
|
3
|
-
import { t } from "../../../helpers/translator"
|
|
4
|
-
import { Icon, IconFillColors } from "../../../icons/Icon"
|
|
5
|
-
import { Listing } from "@bloom-housing/backend-core/types"
|
|
6
|
-
|
|
7
|
-
interface LeasingAgentProps {
|
|
8
|
-
listing: Listing
|
|
9
|
-
managementCompany?: { name: string; website: string }
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const LeasingAgent = (props: LeasingAgentProps) => {
|
|
13
|
-
const listing = props.listing
|
|
14
|
-
|
|
15
|
-
const phoneNumber = listing.leasingAgentPhone
|
|
16
|
-
? `tel:${listing.leasingAgentPhone.replace(/[-()]/g, "")}`
|
|
17
|
-
: ""
|
|
18
|
-
|
|
19
|
-
let managementWebsite = props.managementCompany?.website
|
|
20
|
-
if (managementWebsite && !managementWebsite.startsWith("http")) {
|
|
21
|
-
managementWebsite = `http://${managementWebsite}`
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<section className="aside-block">
|
|
26
|
-
<h4 className="text-caps-underline">{t("leasingAgent.contact")}</h4>
|
|
27
|
-
|
|
28
|
-
{listing.leasingAgentName && <p className="text-xl">{listing.leasingAgentName}</p>}
|
|
29
|
-
{listing.leasingAgentTitle && <p className="text-gray-700">{listing.leasingAgentTitle}</p>}
|
|
30
|
-
{props.managementCompany?.name && (
|
|
31
|
-
<p className="text-gray-700">{props.managementCompany.name}</p>
|
|
32
|
-
)}
|
|
33
|
-
|
|
34
|
-
{listing.leasingAgentPhone && (
|
|
35
|
-
<>
|
|
36
|
-
<p className="mt-5">
|
|
37
|
-
<a href={phoneNumber}>
|
|
38
|
-
<Icon symbol="phone" size="medium" fill={IconFillColors.primary} /> {t("t.call")}{" "}
|
|
39
|
-
{listing.leasingAgentPhone}
|
|
40
|
-
</a>
|
|
41
|
-
</p>
|
|
42
|
-
<p className="text-sm text-gray-700">{t("leasingAgent.dueToHighCallVolume")}</p>
|
|
43
|
-
</>
|
|
44
|
-
)}
|
|
45
|
-
|
|
46
|
-
{listing.leasingAgentEmail && (
|
|
47
|
-
<p className="my-5">
|
|
48
|
-
<a href={`mailto:${listing.leasingAgentEmail}`}>
|
|
49
|
-
<Icon symbol="mail" size="medium" fill={IconFillColors.primary} /> {t("t.email")}
|
|
50
|
-
</a>
|
|
51
|
-
</p>
|
|
52
|
-
)}
|
|
53
|
-
|
|
54
|
-
{managementWebsite && (
|
|
55
|
-
<p className="my-5">
|
|
56
|
-
<a href={managementWebsite} target="_blank" rel="noreferrer noopener">
|
|
57
|
-
<Icon symbol="globe" size="medium" fill={IconFillColors.primary} /> {t("t.website")}
|
|
58
|
-
</a>
|
|
59
|
-
</p>
|
|
60
|
-
)}
|
|
61
|
-
|
|
62
|
-
{listing.leasingAgentAddress && (
|
|
63
|
-
<SidebarAddress
|
|
64
|
-
address={listing.leasingAgentAddress}
|
|
65
|
-
officeHours={listing.leasingAgentOfficeHours}
|
|
66
|
-
/>
|
|
67
|
-
)}
|
|
68
|
-
</section>
|
|
69
|
-
)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export { LeasingAgent as default, LeasingAgent }
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import ReactDOMServer from "react-dom/server"
|
|
3
|
-
import { Icon, IconFillColors } from "../../../icons/Icon"
|
|
4
|
-
import { OneLineAddress, MultiLineAddress, Address } from "../../../helpers/address"
|
|
5
|
-
import { t } from "../../../helpers/translator"
|
|
6
|
-
import Markdown from "markdown-to-jsx"
|
|
7
|
-
|
|
8
|
-
export interface SidebarAddressProps {
|
|
9
|
-
address?: Address
|
|
10
|
-
officeHours?: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const SidebarAddress = (props: SidebarAddressProps) => {
|
|
14
|
-
const { address, officeHours } = props
|
|
15
|
-
let mainAddress = null
|
|
16
|
-
let googleMapsHref = ""
|
|
17
|
-
let hours = <></>
|
|
18
|
-
|
|
19
|
-
if (address?.street) {
|
|
20
|
-
const oneLineAddress = <OneLineAddress address={address} />
|
|
21
|
-
mainAddress = <MultiLineAddress address={address} />
|
|
22
|
-
|
|
23
|
-
googleMapsHref =
|
|
24
|
-
"https://www.google.com/maps/place/" + ReactDOMServer.renderToStaticMarkup(oneLineAddress)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (officeHours) {
|
|
28
|
-
hours = (
|
|
29
|
-
<>
|
|
30
|
-
<h3 className="text-caps-tiny ">{t("leasingAgent.officeHours")}</h3>
|
|
31
|
-
<div className="text-gray-800 text-tiny markdown">
|
|
32
|
-
<Markdown children={officeHours} options={{ disableParsingRawHTML: true }} />
|
|
33
|
-
</div>
|
|
34
|
-
</>
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<>
|
|
40
|
-
{address?.street && (
|
|
41
|
-
<>
|
|
42
|
-
<p className="text-gray-700 mb-1">{mainAddress}</p>
|
|
43
|
-
<p className="mb-4">
|
|
44
|
-
<a href={googleMapsHref} className="inline-block pt-1" target="_blank">
|
|
45
|
-
<Icon symbol="map" size="medium" fill={IconFillColors.primary} />{" "}
|
|
46
|
-
{t("t.getDirections")}
|
|
47
|
-
</a>
|
|
48
|
-
</p>
|
|
49
|
-
</>
|
|
50
|
-
)}
|
|
51
|
-
{hours}
|
|
52
|
-
</>
|
|
53
|
-
)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export { SidebarAddress as default, SidebarAddress }
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
import { t } from "../../../helpers/translator"
|
|
3
|
-
|
|
4
|
-
export interface WaitlistProps {
|
|
5
|
-
isWaitlistOpen: boolean
|
|
6
|
-
waitlistMaxSize?: number | null
|
|
7
|
-
waitlistCurrentSize?: number | null
|
|
8
|
-
waitlistOpenSpots?: number | null
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const WaitlistItem = (props: { className?: string; value: number; text: string }) => (
|
|
12
|
-
<li className={`uppercase text-gray-800 text-tiny ${props.className}`}>
|
|
13
|
-
<span className="text-right w-12 inline-block pr-2">{props.value}</span>
|
|
14
|
-
<span>{props.text}</span>
|
|
15
|
-
</li>
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
const Waitlist = (props: WaitlistProps) => {
|
|
19
|
-
if (!props.isWaitlistOpen) return <></>
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<section className="aside-block is-tinted">
|
|
23
|
-
<h4 className="text-caps-tiny">{t("listings.waitlist.unitsAndWaitlist")}</h4>
|
|
24
|
-
<div>
|
|
25
|
-
<p className="text-tiny text-gray-800 pb-3">{t("listings.waitlist.submitAnApplication")}</p>
|
|
26
|
-
<ul>
|
|
27
|
-
{props.waitlistCurrentSize !== null && props.waitlistCurrentSize !== undefined && (
|
|
28
|
-
<WaitlistItem
|
|
29
|
-
value={props.waitlistCurrentSize}
|
|
30
|
-
text={t("listings.waitlist.currentSize")}
|
|
31
|
-
/>
|
|
32
|
-
)}
|
|
33
|
-
{props.waitlistOpenSpots !== null && props.waitlistOpenSpots !== undefined && (
|
|
34
|
-
<WaitlistItem
|
|
35
|
-
value={props.waitlistOpenSpots}
|
|
36
|
-
text={t("listings.waitlist.openSlots")}
|
|
37
|
-
className={"font-semibold"}
|
|
38
|
-
/>
|
|
39
|
-
)}
|
|
40
|
-
{props.waitlistMaxSize != null && (
|
|
41
|
-
<WaitlistItem value={props.waitlistMaxSize} text={t("listings.waitlist.finalSize")} />
|
|
42
|
-
)}
|
|
43
|
-
</ul>
|
|
44
|
-
</div>
|
|
45
|
-
</section>
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export { Waitlist as default, Waitlist }
|