@bloom-housing/ui-components 4.2.3 → 4.3.0
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 +535 -2
- package/README.md +10 -4
- package/index.ts +14 -10
- package/package.json +6 -4
- package/src/actions/Button.docs.mdx +76 -0
- package/src/actions/Button.scss +58 -61
- package/src/authentication/timeout.tsx +1 -0
- package/src/blocks/DashBlock.tsx +5 -3
- package/src/blocks/DashBlocks.scss +4 -1
- package/src/blocks/FormCard.tsx +1 -1
- package/src/forms/FieldGroup.tsx +18 -17
- package/src/global/app-css.scss +7 -0
- package/src/global/markdown.scss +20 -0
- package/src/global/mixins.scss +66 -49
- package/src/global/tables.scss +236 -58
- package/src/global/text.scss +11 -3
- package/src/global/tokens/borders.scss +15 -0
- package/src/global/tokens/colors.scss +64 -0
- package/src/global/tokens/fonts.scss +45 -0
- package/src/global/tokens/screens.scss +6 -0
- package/src/global/tokens/sizes.scss +48 -0
- package/src/headers/Heading.tsx +2 -0
- package/src/headers/PageHeader.docs.mdx +45 -0
- package/src/headers/PageHeader.scss +30 -17
- package/src/headers/PageHeader.tsx +2 -10
- package/src/headers/SiteHeader.tsx +7 -1
- package/src/helpers/MultiLineAddress.tsx +37 -0
- package/src/helpers/OneLineAddress.tsx +21 -0
- package/src/helpers/tableSummaries.tsx +34 -23
- package/src/locales/general.json +12 -2
- package/src/navigation/FooterNav.scss +8 -3
- package/src/overlays/Drawer.tsx +11 -3
- package/src/overlays/Modal.tsx +16 -7
- package/src/overlays/Overlay.tsx +4 -3
- package/src/page_components/ApplicationTimeline.scss +36 -0
- package/src/page_components/ApplicationTimeline.tsx +33 -0
- package/src/page_components/forgot-password/FormForgotPassword.tsx +5 -4
- package/src/page_components/listing/AdditionalFees.tsx +38 -31
- package/src/page_components/listing/ListingCard.scss +12 -0
- package/src/page_components/listing/ListingCard.tsx +5 -3
- package/src/page_components/listing/ListingMap.tsx +7 -2
- package/src/page_components/listing/UnitTables.tsx +19 -18
- 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/FormSignIn.tsx +2 -1
- package/src/page_components/sign-in/ResendConfirmationModal.tsx +106 -0
- package/src/prototypes/Swatch.tsx +10 -0
- package/src/tables/CategoryTable.tsx +33 -0
- package/src/tables/GroupedTable.tsx +5 -5
- package/src/tables/MinimalTable.tsx +12 -2
- package/src/tables/StackedTable.tsx +38 -26
- package/src/tables/StandardTable.tsx +26 -10
- package/tailwind.config.js +76 -81
- package/tailwind.tosass.js +2 -1
- package/src/helpers/address.tsx +0 -46
- 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
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bloom-s0_5: 0.125rem;
|
|
3
|
+
--bloom-s1: 0.25rem;
|
|
4
|
+
--bloom-s1_5: 0.375rem;
|
|
5
|
+
--bloom-s2: 0.5rem;
|
|
6
|
+
--bloom-s2_5: 0.625rem;
|
|
7
|
+
--bloom-s3: 0.75rem;
|
|
8
|
+
--bloom-s3_5: 0.875;
|
|
9
|
+
--bloom-s4: 1rem;
|
|
10
|
+
--bloom-s5: 1.25rem;
|
|
11
|
+
--bloom-s6: 1.5rem;
|
|
12
|
+
--bloom-s7: 1.75rem;
|
|
13
|
+
--bloom-s8: 2rem;
|
|
14
|
+
--bloom-s9: 2.25rem;
|
|
15
|
+
--bloom-s10: 2.5rem;
|
|
16
|
+
--bloom-s11: 2.75rem;
|
|
17
|
+
--bloom-s12: 3rem;
|
|
18
|
+
--bloom-s14: 3.5rem;
|
|
19
|
+
--bloom-s16: 4rem;
|
|
20
|
+
--bloom-s20: 5rem;
|
|
21
|
+
--bloom-s24: 6rem;
|
|
22
|
+
--bloom-s28: 7rem;
|
|
23
|
+
--bloom-s32: 8rem;
|
|
24
|
+
--bloom-s36: 9rem;
|
|
25
|
+
--bloom-s40: 10rem;
|
|
26
|
+
--bloom-s44: 11rem;
|
|
27
|
+
--bloom-s48: 12rem;
|
|
28
|
+
--bloom-s52: 13rem;
|
|
29
|
+
--bloom-s56: 14rem;
|
|
30
|
+
--bloom-s60: 15rem;
|
|
31
|
+
--bloom-s64: 16rem;
|
|
32
|
+
--bloom-s72: 18rem;
|
|
33
|
+
--bloom-s80: 20rem;
|
|
34
|
+
--bloom-s96: 24rem;
|
|
35
|
+
|
|
36
|
+
--bloom-width-xs: 20rem;
|
|
37
|
+
--bloom-width-sm: 24rem;
|
|
38
|
+
--bloom-width-md: 28rem;
|
|
39
|
+
--bloom-width-lg: 32rem;
|
|
40
|
+
--bloom-width-xl: 36rem;
|
|
41
|
+
--bloom-width-2xl: 42rem;
|
|
42
|
+
--bloom-width-3xl: 48rem;
|
|
43
|
+
--bloom-width-4xl: 56rem;
|
|
44
|
+
--bloom-width-5xl: 64rem;
|
|
45
|
+
--bloom-width-6xl: 72rem;
|
|
46
|
+
--bloom-width-7xl: 80rem;
|
|
47
|
+
--bloom-width-prose: 65ch;
|
|
48
|
+
}
|
package/src/headers/Heading.tsx
CHANGED
|
@@ -15,6 +15,8 @@ const HeaderStyleMap = {
|
|
|
15
15
|
tableHeader: "table-header",
|
|
16
16
|
tableSubheader: "table-subheader",
|
|
17
17
|
sidebarHeader: "text-caps-underline",
|
|
18
|
+
categoryHeader: "category-header",
|
|
19
|
+
sidebarSubHeader: "text-caps-tiny",
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
const Heading = (props: HeadingProps) => {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Canvas, Story, ArgsTable } from "@storybook/addon-docs"
|
|
2
|
+
import { PageHeader } from "./PageHeader"
|
|
3
|
+
|
|
4
|
+
# Page Header
|
|
5
|
+
|
|
6
|
+
The page header component displays a title, with an optional subtitle and/or arbitary children elements.
|
|
7
|
+
|
|
8
|
+
<Canvas>
|
|
9
|
+
<Story id="headers-page-header--with-content" />
|
|
10
|
+
</Canvas>
|
|
11
|
+
|
|
12
|
+
<br />
|
|
13
|
+
<br />
|
|
14
|
+
|
|
15
|
+
## Variants
|
|
16
|
+
|
|
17
|
+
### Inverse
|
|
18
|
+
|
|
19
|
+
Set the `inverse` property to `true`.
|
|
20
|
+
|
|
21
|
+
<Canvas>
|
|
22
|
+
<Story id="headers-page-header--inversed" />
|
|
23
|
+
</Canvas>
|
|
24
|
+
|
|
25
|
+
## Component Properties
|
|
26
|
+
|
|
27
|
+
<ArgsTable of={PageHeader} />
|
|
28
|
+
|
|
29
|
+
## Theming Variables
|
|
30
|
+
|
|
31
|
+
<Canvas>
|
|
32
|
+
<Story id="headers-page-header--style-overrides" />
|
|
33
|
+
</Canvas>
|
|
34
|
+
|
|
35
|
+
You can apply CSS variables to the `.page-header` selector to customize the appearance of the component.
|
|
36
|
+
|
|
37
|
+
| Name | Type | Description | Default |
|
|
38
|
+
| ---------------------------- | ----- | --------------------------------------------------------- | ------------------------------- |
|
|
39
|
+
| `--background-color` | Color | The background of the header | `--bloom-color-primary-lighter` |
|
|
40
|
+
| `--border-color` | Color | The color of the top border | `--bloom-color-gray-450` |
|
|
41
|
+
| `--text-color` | Color | The color of text inside the header | `inherit` |
|
|
42
|
+
| `--inverse-background-color` | Color | The `inverse` variant background | `--bloom-color-primary-darker` |
|
|
43
|
+
| `--inverse-border-color` | Color | The `inverse` variant color of the top border | `--bloom-color-primary` |
|
|
44
|
+
| `--inverse-text-color` | Color | The `inverse` variant color of text | `--bloom-color-white` |
|
|
45
|
+
| `--title-font-size` | Size | The font size of the title (only on medium+ size screens) | `--bloom-font-size-5xl` |
|
|
@@ -1,34 +1,47 @@
|
|
|
1
1
|
.page-header {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
/* Component Variables */
|
|
3
|
+
--background-color: var(--bloom-color-primary-lighter);
|
|
4
|
+
--border-color: var(--bloom-color-gray-450);
|
|
5
|
+
--text-color: inherit;
|
|
6
|
+
--inverse-background-color: var(--bloom-color-primary-darker);
|
|
7
|
+
--inverse-border-color: var(--bloom-color-primary);
|
|
8
|
+
--inverse-text-color: var(--bloom-color-white);
|
|
9
|
+
--title-font-size: var(--bloom-font-size-5xl);
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
/* Base Styles */
|
|
12
|
+
padding: var(--bloom-s8) 0;
|
|
13
|
+
background-color: var(--background-color);
|
|
14
|
+
border-top: var(--bloom-border-1) solid var(--border-color);
|
|
15
|
+
color: var(--text-color);
|
|
16
|
+
|
|
17
|
+
@media (min-width: $screen-sm) {
|
|
18
|
+
padding: var(--bloom-s10) 0;
|
|
8
19
|
}
|
|
9
20
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
21
|
+
/* Variants */
|
|
22
|
+
&.is-inverse {
|
|
23
|
+
--background-color: var(--inverse-background-color);
|
|
24
|
+
--border-color: var(--inverse-border-color);
|
|
25
|
+
--text-color: var(--inverse-text-color);
|
|
13
26
|
}
|
|
14
27
|
}
|
|
15
28
|
|
|
16
29
|
.page-header__group {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
30
|
+
padding: 0 var(--bloom-s5);
|
|
31
|
+
margin: auto;
|
|
32
|
+
max-width: var(--bloom-width-5xl);
|
|
20
33
|
}
|
|
21
34
|
|
|
22
35
|
.page-header__title {
|
|
23
|
-
|
|
36
|
+
text-align: center;
|
|
24
37
|
|
|
25
|
-
@screen
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
@media (min-width: $screen-md) {
|
|
39
|
+
font-size: var(--title-font-size);
|
|
40
|
+
text-align: left;
|
|
28
41
|
}
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
.page-header__lead {
|
|
32
|
-
|
|
33
|
-
|
|
45
|
+
margin: auto;
|
|
46
|
+
max-width: var(--bloom-width-5xl);
|
|
34
47
|
}
|
|
@@ -12,16 +12,8 @@ export interface PageHeaderProps {
|
|
|
12
12
|
|
|
13
13
|
const PageHeader = (props: PageHeaderProps) => {
|
|
14
14
|
const classNames = ["page-header"]
|
|
15
|
-
if (props.
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (props.inverse) {
|
|
20
|
-
classNames.push("bg-primary-dark")
|
|
21
|
-
classNames.push("text-white")
|
|
22
|
-
} else {
|
|
23
|
-
classNames.push("bg-primary-lighter")
|
|
24
|
-
}
|
|
15
|
+
if (props.inverse) classNames.push("is-inverse")
|
|
16
|
+
if (props.className) classNames.push(...props.className.split(" "))
|
|
25
17
|
|
|
26
18
|
return (
|
|
27
19
|
<header className={classNames.join(" ")}>
|
|
@@ -24,6 +24,7 @@ export interface SiteHeaderProps {
|
|
|
24
24
|
dropdownItemClassName?: string
|
|
25
25
|
homeURL: string
|
|
26
26
|
imageOnly?: boolean
|
|
27
|
+
languageNavLabel?: string
|
|
27
28
|
languages?: LangItem[]
|
|
28
29
|
logoClass?: string
|
|
29
30
|
logoSrc: string
|
|
@@ -142,6 +143,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
|
|
|
142
143
|
}
|
|
143
144
|
dropdownOptionKeyDown(event, index)
|
|
144
145
|
}}
|
|
146
|
+
data-test-id={`${option.title}-${index}`}
|
|
145
147
|
>
|
|
146
148
|
{dropdownOptionContent(option)}
|
|
147
149
|
</button>
|
|
@@ -295,6 +297,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
|
|
|
295
297
|
className={`navbar-link ${props.menuItemClassName && props.menuItemClassName}`}
|
|
296
298
|
href={menuLink.href}
|
|
297
299
|
key={`${menuLink.title}-${index}`}
|
|
300
|
+
data-test-id={`${menuLink.title}-${index}`}
|
|
298
301
|
>
|
|
299
302
|
{menuContent}
|
|
300
303
|
</LinkComponent>
|
|
@@ -333,6 +336,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
|
|
|
333
336
|
}}
|
|
334
337
|
onMouseEnter={() => changeMenuShow(menuLink.title, activeMenus, setActiveMenus)}
|
|
335
338
|
onMouseLeave={() => changeMenuShow(menuLink.title, activeMenus, setActiveMenus)}
|
|
339
|
+
data-test-id={`${menuLink.title}-${index}`}
|
|
336
340
|
>
|
|
337
341
|
{menuContent}
|
|
338
342
|
</span>
|
|
@@ -423,7 +427,9 @@ const SiteHeader = (props: SiteHeaderProps) => {
|
|
|
423
427
|
|
|
424
428
|
return (
|
|
425
429
|
<header className={"site-header"}>
|
|
426
|
-
{props.languages &&
|
|
430
|
+
{props.languages && (
|
|
431
|
+
<LanguageNav ariaLabel={props.languageNavLabel} languages={props.languages} />
|
|
432
|
+
)}
|
|
427
433
|
|
|
428
434
|
<div className={`navbar-notice ${!props.noticeMobile && `navbar-notice-hide`}`}>
|
|
429
435
|
<div className="navbar-notice__text">{props.notice ?? ""}</div>
|
|
@@ -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,8 +1,9 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
2
|
import { t } from "./translator"
|
|
3
3
|
import { UnitSummary } from "@bloom-housing/backend-core/types"
|
|
4
|
+
import { StandardTableData } from "../tables/StandardTable"
|
|
4
5
|
|
|
5
|
-
export const unitSummariesTable = (summaries: UnitSummary[]) => {
|
|
6
|
+
export const unitSummariesTable = (summaries: UnitSummary[]): StandardTableData => {
|
|
6
7
|
const unitSummaries = summaries?.map((unitSummary) => {
|
|
7
8
|
const unitPluralization = unitSummary.totalAvailable == 1 ? t("t.unit") : t("t.units")
|
|
8
9
|
const minIncome =
|
|
@@ -10,7 +11,8 @@ export const unitSummariesTable = (summaries: UnitSummary[]) => {
|
|
|
10
11
|
<strong>{unitSummary.minIncomeRange.min}</strong>
|
|
11
12
|
) : (
|
|
12
13
|
<>
|
|
13
|
-
<strong>{unitSummary.minIncomeRange.min}</strong>
|
|
14
|
+
<strong>{unitSummary.minIncomeRange.min}</strong>
|
|
15
|
+
{` ${t("t.to")} `}
|
|
14
16
|
<strong>{unitSummary.minIncomeRange.max}</strong>
|
|
15
17
|
</>
|
|
16
18
|
)
|
|
@@ -24,7 +26,9 @@ export const unitSummariesTable = (summaries: UnitSummary[]) => {
|
|
|
24
26
|
</>
|
|
25
27
|
) : (
|
|
26
28
|
<>
|
|
27
|
-
<strong>{rentMin}</strong>
|
|
29
|
+
<strong>{rentMin}</strong>
|
|
30
|
+
{` ${t("t.to")} `}
|
|
31
|
+
<strong>{rentMax}</strong>
|
|
28
32
|
{unit}
|
|
29
33
|
</>
|
|
30
34
|
)
|
|
@@ -40,32 +44,39 @@ export const unitSummariesTable = (summaries: UnitSummary[]) => {
|
|
|
40
44
|
: getRent(unitSummary.rentRange.min, unitSummary.rentRange.max)
|
|
41
45
|
|
|
42
46
|
return {
|
|
43
|
-
unitType:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
47
|
+
unitType: {
|
|
48
|
+
content: <strong>{t(`listings.unitTypes.${unitSummary.unitType?.name}`)}</strong>,
|
|
49
|
+
},
|
|
50
|
+
minimumIncome: {
|
|
51
|
+
content: (
|
|
52
|
+
<span>
|
|
53
|
+
{minIncome}
|
|
54
|
+
{` ${t("t.perMonth")}`}
|
|
55
|
+
</span>
|
|
56
|
+
),
|
|
57
|
+
},
|
|
58
|
+
rent: { content: <span>{rent}</span> },
|
|
59
|
+
availability: {
|
|
60
|
+
content: (
|
|
61
|
+
<span>
|
|
62
|
+
{unitSummary.totalAvailable > 0 ? (
|
|
63
|
+
<>
|
|
64
|
+
<strong>{unitSummary.totalAvailable}</strong> {unitPluralization}
|
|
65
|
+
</>
|
|
66
|
+
) : (
|
|
67
|
+
<span className="uppercase">{t("listings.waitlist.label")}</span>
|
|
68
|
+
)}
|
|
69
|
+
</span>
|
|
70
|
+
),
|
|
71
|
+
},
|
|
61
72
|
}
|
|
62
73
|
})
|
|
63
74
|
|
|
64
75
|
return unitSummaries
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
export const getSummariesTable = (summaries: UnitSummary[]) => {
|
|
68
|
-
let unitSummaries = []
|
|
78
|
+
export const getSummariesTable = (summaries: UnitSummary[]): StandardTableData => {
|
|
79
|
+
let unitSummaries: StandardTableData = []
|
|
69
80
|
|
|
70
81
|
if (summaries?.length > 0) {
|
|
71
82
|
unitSummaries = unitSummariesTable(summaries)
|
package/src/locales/general.json
CHANGED
|
@@ -98,6 +98,7 @@
|
|
|
98
98
|
"application.contact.yourPhoneNumber": "Your Phone Number",
|
|
99
99
|
"application.contact.zip": "Zip",
|
|
100
100
|
"application.contact.zipCode": "Zipcode",
|
|
101
|
+
"application.details.adaPriorities": "ADA Priorities Selected",
|
|
101
102
|
"application.edited": "Edited",
|
|
102
103
|
"application.financial.income.instruction1": "Add up your total gross (pre-tax) household income from wages, benefits and other sources from all household members.",
|
|
103
104
|
"application.financial.income.instruction2": "You only need to provide an estimated total right now. The actual total will be calculated if you are selected.",
|
|
@@ -353,22 +354,31 @@
|
|
|
353
354
|
"application.referralApplication.furtherInformation": "For further information",
|
|
354
355
|
"application.referralApplication.instructions": "The permanent supportive housing units are referred directly through <JURISDICTION> Coordinated Entry System. Households experiencing homelessness can call <PHONE_NUMBER> in order to get connected to an Access Point to learn more about the coordinated entry system and access housing-related resources and information.",
|
|
355
356
|
"application.referralApplication.phoneNumber": "211",
|
|
357
|
+
"application.review.confirmation.applicationReceived": "Application \nreceived",
|
|
358
|
+
"application.review.confirmation.applicationsClosed": "Application \nclosed",
|
|
359
|
+
"application.review.confirmation.applicationsRanked": "Application \nranked",
|
|
356
360
|
"application.review.confirmation.browseMore": "Browse more listings",
|
|
357
361
|
"application.review.confirmation.createAccountParagraph": "Creating an account will save your information for future applications, and you can check the status of this application anytime.",
|
|
362
|
+
"application.review.confirmation.createAccount": "### Would you like to create an account?\n\nCreating an account will save your information for future applications, and you can check the status of this application anytime.",
|
|
358
363
|
"application.review.confirmation.createAccountTitle": "Would you like to create an account?",
|
|
359
364
|
"application.review.confirmation.doNotSubmitTitle": "Do not submit another application for this listing.",
|
|
360
365
|
"application.review.confirmation.imdone": "No thanks, I'm done.",
|
|
361
|
-
"application.review.confirmation.lotteryNumber": "
|
|
366
|
+
"application.review.confirmation.lotteryNumber": "Your confirmation number",
|
|
362
367
|
"application.review.confirmation.needToUpdate": "If you need to update information on your application, do not apply again. Contact the agent if you did not receive an email confirmation.",
|
|
363
|
-
"application.review.confirmation.pleaseWriteNumber": "Please write down your application number and keep it in a safe place. We have also emailed this number to you if you provided an email address.",
|
|
368
|
+
"application.review.confirmation.pleaseWriteNumber": "Please write down your application number and keep it in a safe place. We have also emailed this number to you if you have provided an email address.",
|
|
364
369
|
"application.review.confirmation.print": "View submitted application and print a copy.",
|
|
365
370
|
"application.review.confirmation.title": "Thanks. We have received your application for ",
|
|
371
|
+
"application.review.confirmation.needToMakeUpdates": "### Need to make updates?\n\nIf you need to update information on your application, do not apply again. Instead, contact the agent for this listing.\n\n**%{agentName}** \n%{agentPhone} \n%{agentEmail}\n\n**Office Hours** \n%{agentOfficeHours}\n\nContact the agent if you did not receive an email confirmation.",
|
|
366
372
|
"application.review.confirmation.whatExpectFirstParagraph.attend": " You do not need to attend the housing lottery. Results will be posted ",
|
|
367
373
|
"application.review.confirmation.whatExpectFirstParagraph.held": "The lottery will be held on ",
|
|
368
374
|
"application.review.confirmation.whatExpectFirstParagraph.listing": "on the listing. ",
|
|
369
375
|
"application.review.confirmation.whatExpectFirstParagraph.refer": "Please refer to the listing for the lottery results date.",
|
|
370
376
|
"application.review.confirmation.whatExpectSecondparagraph": "Applicants will be contacted in order until vacancies are filled. Should your application be chosen, be prepared to fill out a more detailed application and provide required supporting documents.",
|
|
371
377
|
"application.review.confirmation.whatExpectTitle": "What to expect next",
|
|
378
|
+
"application.review.confirmation.whatHappensNext": "### What happens next?\n\n* After all applications are submitted, the property manager will begin processing applications.\n\n* %{reviewOrder}\n\n* If you are contacted for an interview, you will need to fill out a more detailed application and provide supporting documents.",
|
|
379
|
+
"application.review.confirmation.eligibleApplicants.FCFS": "Eligibile applicants will be contacted by on a **first come first serve** basis until vacancies are filled",
|
|
380
|
+
"application.review.confirmation.eligibleApplicants.lotteryDate": "The lottery will be held on **%{lotteryDate}**.",
|
|
381
|
+
"application.review.confirmation.eligibleApplicants.lottery": "Eligible applicants will be contacted by the agent in lottery rank order until vacancies are filled",
|
|
372
382
|
"application.review.demographics.ethnicityLabel": "Which best describes your ethnicity?",
|
|
373
383
|
"application.review.demographics.ethnicityOptions.hispanicLatino": "Hispanic / Latino",
|
|
374
384
|
"application.review.demographics.ethnicityOptions.notHispanicLatino": "Not Hispanic / Latino",
|
|
@@ -22,26 +22,31 @@
|
|
|
22
22
|
.footer-sock__inner {
|
|
23
23
|
@apply max-w-5xl;
|
|
24
24
|
@apply m-auto;
|
|
25
|
-
|
|
25
|
+
justify-content: space-between;
|
|
26
26
|
@screen lg {
|
|
27
27
|
@apply flex;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
.footer-copyright {
|
|
32
|
+
width: auto;
|
|
33
|
+
flex-shrink: 0;
|
|
32
34
|
@screen lg {
|
|
33
|
-
@apply w-6/12;
|
|
34
35
|
@apply text-left;
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
.footer-nav {
|
|
39
40
|
@apply mt-5;
|
|
41
|
+
width: auto;
|
|
40
42
|
|
|
41
43
|
@screen lg {
|
|
42
44
|
@apply mt-0;
|
|
43
|
-
@apply w-6/12;
|
|
44
45
|
@apply text-right;
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: flex-start;
|
|
48
|
+
flex-wrap: wrap;
|
|
49
|
+
justify-content: end;
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
}
|
package/src/overlays/Drawer.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React, { useRef } from "react"
|
|
2
2
|
import "./Drawer.scss"
|
|
3
3
|
import { Icon } from "../icons/Icon"
|
|
4
4
|
import { Overlay, OverlayProps } from "./Overlay"
|
|
@@ -6,6 +6,7 @@ import { Tag } from "../text/Tag"
|
|
|
6
6
|
import { AppearanceStyleType, AppearanceSizeType } from "../global/AppearanceTypes"
|
|
7
7
|
import { AlertTypes } from "../notifications/alertTypes"
|
|
8
8
|
import { AlertBox } from "../notifications"
|
|
9
|
+
import { nanoid } from "nanoid"
|
|
9
10
|
|
|
10
11
|
export enum DrawerSide {
|
|
11
12
|
left = "left",
|
|
@@ -28,18 +29,25 @@ const Drawer = (props: DrawerProps) => {
|
|
|
28
29
|
const drawerClasses = ["drawer"]
|
|
29
30
|
if (props.className) drawerClasses.push(props.className)
|
|
30
31
|
|
|
32
|
+
const uniqueIdRef = useRef(nanoid())
|
|
33
|
+
|
|
31
34
|
return (
|
|
32
35
|
<Overlay
|
|
33
|
-
|
|
36
|
+
ariaLabelledBy={uniqueIdRef.current}
|
|
34
37
|
ariaDescription={props.ariaDescription}
|
|
35
38
|
open={props.open}
|
|
36
39
|
onClose={props.onClose}
|
|
37
40
|
backdrop={props.backdrop}
|
|
38
41
|
className={"has-drawer" + (props.direction == DrawerSide.left ? " is-direction-left" : "")}
|
|
42
|
+
role="dialog"
|
|
39
43
|
>
|
|
40
44
|
<div className={drawerClasses.join(" ")}>
|
|
41
45
|
<header className="drawer__header">
|
|
42
|
-
{props.title &&
|
|
46
|
+
{props.title && (
|
|
47
|
+
<h1 className="drawer__title" id={uniqueIdRef.current}>
|
|
48
|
+
{props.title}
|
|
49
|
+
</h1>
|
|
50
|
+
)}
|
|
43
51
|
{props.headerTag && (
|
|
44
52
|
<Tag
|
|
45
53
|
pillStyle={true}
|
package/src/overlays/Modal.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import React from "react"
|
|
1
|
+
import React, { useRef } from "react"
|
|
2
2
|
import "./Modal.scss"
|
|
3
3
|
import { Icon } from "../icons/Icon"
|
|
4
4
|
import { Overlay, OverlayProps } from "./Overlay"
|
|
5
|
+
import { nanoid } from "nanoid"
|
|
5
6
|
|
|
6
7
|
export interface ModalProps extends Omit<OverlayProps, "children"> {
|
|
7
8
|
title: string
|
|
@@ -9,12 +10,17 @@ export interface ModalProps extends Omit<OverlayProps, "children"> {
|
|
|
9
10
|
hideCloseIcon?: boolean
|
|
10
11
|
children?: React.ReactNode
|
|
11
12
|
slim?: boolean
|
|
13
|
+
role?: string
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
const ModalHeader = (props: { title: string }) => (
|
|
15
|
-
|
|
16
|
-
<
|
|
17
|
-
|
|
16
|
+
const ModalHeader = (props: { title: string; uniqueId?: string }) => (
|
|
17
|
+
<>
|
|
18
|
+
<header className="modal__inner">
|
|
19
|
+
<h1 className="modal__title" id={props.uniqueId}>
|
|
20
|
+
{props.title}
|
|
21
|
+
</h1>
|
|
22
|
+
</header>
|
|
23
|
+
</>
|
|
18
24
|
)
|
|
19
25
|
|
|
20
26
|
const ModalFooter = (props: { actions: React.ReactNode[] }) => (
|
|
@@ -28,17 +34,20 @@ const ModalFooter = (props: { actions: React.ReactNode[] }) => (
|
|
|
28
34
|
)
|
|
29
35
|
|
|
30
36
|
export const Modal = (props: ModalProps) => {
|
|
37
|
+
const uniqueIdRef = useRef(nanoid())
|
|
38
|
+
|
|
31
39
|
return (
|
|
32
40
|
<Overlay
|
|
33
|
-
|
|
41
|
+
ariaLabelledBy={uniqueIdRef.current}
|
|
34
42
|
ariaDescription={props.ariaDescription}
|
|
35
43
|
open={props.open}
|
|
36
44
|
onClose={props.onClose}
|
|
37
45
|
backdrop={props.backdrop}
|
|
38
46
|
slim={props.slim}
|
|
47
|
+
role={props.role ? props.role : "dialog"}
|
|
39
48
|
>
|
|
40
49
|
<div className="modal">
|
|
41
|
-
<ModalHeader title={props.title} />
|
|
50
|
+
<ModalHeader title={props.title} uniqueId={uniqueIdRef.current} />
|
|
42
51
|
|
|
43
52
|
<section className="modal__inner">
|
|
44
53
|
{typeof props.children === "string" ? (
|
package/src/overlays/Overlay.tsx
CHANGED
|
@@ -8,13 +8,14 @@ import { CSSTransition } from "react-transition-group"
|
|
|
8
8
|
|
|
9
9
|
export type OverlayProps = {
|
|
10
10
|
open?: boolean
|
|
11
|
-
|
|
11
|
+
ariaLabelledBy?: string
|
|
12
12
|
ariaDescription?: string
|
|
13
13
|
className?: string
|
|
14
14
|
backdrop?: boolean
|
|
15
15
|
onClose?: () => void
|
|
16
16
|
children: React.ReactNode
|
|
17
17
|
slim?: boolean
|
|
18
|
+
role?: string
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
const OverlayInner = (props: OverlayProps) => {
|
|
@@ -31,8 +32,8 @@ const OverlayInner = (props: OverlayProps) => {
|
|
|
31
32
|
return (
|
|
32
33
|
<div
|
|
33
34
|
className={classNames.join(" ")}
|
|
34
|
-
role=
|
|
35
|
-
aria-labelledby={props.
|
|
35
|
+
role={props.role}
|
|
36
|
+
aria-labelledby={props.ariaLabelledBy}
|
|
36
37
|
aria-describedby={props.ariaDescription}
|
|
37
38
|
onClick={(e) => {
|
|
38
39
|
if (e.target === e.currentTarget) closeHandler()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
.markdown ul.application-timeline {
|
|
2
|
+
@apply mb-8;
|
|
3
|
+
@apply ml-0;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.application-timeline {
|
|
7
|
+
.progress-nav__item {
|
|
8
|
+
@apply pt-0;
|
|
9
|
+
|
|
10
|
+
text-transform: unset;
|
|
11
|
+
|
|
12
|
+
.absolute {
|
|
13
|
+
margin-top: 0.45rem;
|
|
14
|
+
z-index: 2;
|
|
15
|
+
margin-left: -0.4rem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
p {
|
|
19
|
+
padding-top: 3.8em;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.progress-nav__item.is-active::before,
|
|
24
|
+
.progress-nav__item.is-disabled::before {
|
|
25
|
+
height: 2rem;
|
|
26
|
+
width: 2rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.progress-nav__item.is-active::before {
|
|
30
|
+
@apply bg-green-700;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.progress-nav__item::after {
|
|
34
|
+
top: 1rem;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import Markdown from "markdown-to-jsx"
|
|
3
|
+
import { Icon } from "../icons/Icon"
|
|
4
|
+
import { t } from "../helpers/translator"
|
|
5
|
+
import "./ApplicationTimeline.scss"
|
|
6
|
+
|
|
7
|
+
const ApplicationTimeline = () => (
|
|
8
|
+
<ul
|
|
9
|
+
className="progress-nav application-timeline"
|
|
10
|
+
aria-label="Steps of processing your application"
|
|
11
|
+
>
|
|
12
|
+
<li className="progress-nav__item is-active" aria-current="step">
|
|
13
|
+
<span className="text-white absolute">
|
|
14
|
+
<Icon symbol="check" size="base" />
|
|
15
|
+
</span>
|
|
16
|
+
<Markdown className="font-bold" options={{ disableParsingRawHTML: true }}>
|
|
17
|
+
{t("application.review.confirmation.applicationReceived")}
|
|
18
|
+
</Markdown>
|
|
19
|
+
</li>
|
|
20
|
+
<li className="progress-nav__item is-disabled">
|
|
21
|
+
<Markdown options={{ disableParsingRawHTML: true }}>
|
|
22
|
+
{t("application.review.confirmation.applicationsClosed")}
|
|
23
|
+
</Markdown>
|
|
24
|
+
</li>
|
|
25
|
+
<li className="progress-nav__item is-disabled">
|
|
26
|
+
<Markdown options={{ disableParsingRawHTML: true }}>
|
|
27
|
+
{t("application.review.confirmation.applicationsRanked")}
|
|
28
|
+
</Markdown>
|
|
29
|
+
</li>
|
|
30
|
+
</ul>
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
export { ApplicationTimeline }
|