@bloom-housing/ui-components 4.2.2-alpha.2 → 4.2.2-alpha.22
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 +192 -0
- package/README.md +10 -4
- package/index.ts +3 -0
- package/package.json +5 -3
- 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/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 +9 -1
- 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 +1 -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 +4 -1
- package/src/helpers/address.tsx +5 -4
- package/src/helpers/tableSummaries.tsx +34 -23
- package/src/locales/general.json +9 -2
- package/src/navigation/FooterNav.scss +2 -1
- 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/UnitTables.tsx +19 -18
- 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
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bloom-color-white: #ffffff;
|
|
3
|
+
--bloom-color-black: #000000;
|
|
4
|
+
|
|
5
|
+
--bloom-color-red-800: #b21d38;
|
|
6
|
+
--bloom-color-red-700: #e41d3d;
|
|
7
|
+
--bloom-color-red-300: #f9d2d8;
|
|
8
|
+
|
|
9
|
+
--bloom-color-green-800: #216e1f;
|
|
10
|
+
--bloom-color-green-700: #2e8540;
|
|
11
|
+
--bloom-color-green-300: #b4e5be;
|
|
12
|
+
|
|
13
|
+
--bloom-color-blue-800: #205493;
|
|
14
|
+
--bloom-color-blue-700: #0067be;
|
|
15
|
+
--bloom-color-blue-600: #0077da;
|
|
16
|
+
--bloom-color-blue-300: #daeeff;
|
|
17
|
+
--bloom-color-blue-200: #f5f8f9;
|
|
18
|
+
|
|
19
|
+
--bloom-color-yellow-800: #e5a000;
|
|
20
|
+
--bloom-color-yellow-700: #fdb81e;
|
|
21
|
+
--bloom-color-yellow-300: #fee8b6;
|
|
22
|
+
|
|
23
|
+
--bloom-color-gray-950: #242c2e;
|
|
24
|
+
--bloom-color-gray-900: #222222;
|
|
25
|
+
--bloom-color-gray-850: #333333;
|
|
26
|
+
--bloom-color-gray-800: #30383a;
|
|
27
|
+
--bloom-color-gray-750: #555555;
|
|
28
|
+
--bloom-color-gray-700: #767676;
|
|
29
|
+
--bloom-color-gray-600: #999999;
|
|
30
|
+
--bloom-color-gray-550: #aaaaaa;
|
|
31
|
+
--bloom-color-gray-500: #cccccc;
|
|
32
|
+
--bloom-color-gray-450: #dedee0;
|
|
33
|
+
--bloom-color-gray-400: #efefef;
|
|
34
|
+
--bloom-color-gray-300: #f6f6f6;
|
|
35
|
+
--bloom-color-gray-200: #f7f7f7;
|
|
36
|
+
--bloom-color-gray-100: #f9f9f9;
|
|
37
|
+
|
|
38
|
+
--bloom-color-primary: var(--bloom-color-blue-600);
|
|
39
|
+
--bloom-color-primary-dark: var(--bloom-color-blue-700);
|
|
40
|
+
--bloom-color-primary-darker: var(--bloom-color-blue-800);
|
|
41
|
+
--bloom-color-primary-light: var(--bloom-color-blue-300);
|
|
42
|
+
--bloom-color-primary-lighter: var(--bloom-color-blue-200);
|
|
43
|
+
|
|
44
|
+
--bloom-color-secondary: var(--bloom-color-blue-700);
|
|
45
|
+
--bloom-color-alert: var(--bloom-color-red-700);
|
|
46
|
+
--bloom-color-alert-light: var(--bloom-color-red-300);
|
|
47
|
+
--bloom-color-alert-dark: var(--bloom-color-red-800);
|
|
48
|
+
--bloom-color-success: var(--bloom-color-green-700);
|
|
49
|
+
--bloom-color-success-light: var(--bloom-color-green-300);
|
|
50
|
+
--bloom-color-success-dark: var(--bloom-color-green-800);
|
|
51
|
+
--bloom-color-warn: var(--bloom-color-yellow-700);
|
|
52
|
+
--bloom-color-warn-light: var(--bloom-color-yellow-300);
|
|
53
|
+
--bloom-color-warn-dark: var(--bloom-color-yellow-800);
|
|
54
|
+
|
|
55
|
+
--bloom-color-accent-cool: #00bed5;
|
|
56
|
+
--bloom-color-accent-cool-light: #c8f1ff;
|
|
57
|
+
--bloom-color-accent-cool-dark: #009db0;
|
|
58
|
+
--bloom-color-accent-warm: #ff6627;
|
|
59
|
+
--bloom-color-accent-warm-dark: #d54309;
|
|
60
|
+
--bloom-color-accent-warm-light: #ffd2c0;
|
|
61
|
+
--bloom-color-accent-warm-lighter: #fff7f3;
|
|
62
|
+
|
|
63
|
+
--bloom-color-lush: #99cd00;
|
|
64
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--bloom-font-sans: "Open Sans", Helvetica, Arial, Verdana, sans-serif;
|
|
3
|
+
--bloom-font-serif: "Droid Serif", Georgia, Times, serif;
|
|
4
|
+
--bloom-font-alt-sans: Lato, Helvetica, Arial, Verdana, sans-serif;
|
|
5
|
+
--bloom-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
|
|
6
|
+
"Courier New", monospace;
|
|
7
|
+
|
|
8
|
+
--bloom-font-size-2xs: 0.6875rem;
|
|
9
|
+
--bloom-font-size-xs: 0.75rem;
|
|
10
|
+
--bloom-font-size-sm: 0.8125rem;
|
|
11
|
+
--bloom-font-size-tiny: 0.875rem;
|
|
12
|
+
--bloom-font-size-base: 1rem;
|
|
13
|
+
--bloom-font-size-lg: 1.25rem;
|
|
14
|
+
--bloom-font-size-xl: 1.375rem;
|
|
15
|
+
--bloom-font-size-2xl: 1.5rem;
|
|
16
|
+
--bloom-font-size-3xl: 1.625rem;
|
|
17
|
+
--bloom-font-size-4xl: 2rem;
|
|
18
|
+
--bloom-font-size-5xl: 2.5rem;
|
|
19
|
+
--bloom-font-size-6xl: 3rem;
|
|
20
|
+
--bloom-font-size-6_5xl: 4rem;
|
|
21
|
+
--bloom-font-size-7xl: 4.5rem;
|
|
22
|
+
|
|
23
|
+
--bloom-letter-spacing-tightest: -0.075em;
|
|
24
|
+
--bloom-letter-spacing-tighter: -0.05em;
|
|
25
|
+
--bloom-letter-spacing-tight: -0.025em;
|
|
26
|
+
--bloom-letter-spacing-wide: 0.025em;
|
|
27
|
+
--bloom-letter-spacing-wider: 0.05em;
|
|
28
|
+
--bloom-letter-spacing-widest: 0.12em;
|
|
29
|
+
--bloom-letter-spacing-ultrawide: 0.25em;
|
|
30
|
+
|
|
31
|
+
--bloom-line-height-3: 0.75rem;
|
|
32
|
+
--bloom-line-height-4: 1rem;
|
|
33
|
+
--bloom-line-height-5: 1.25rem;
|
|
34
|
+
--bloom-line-height-6: 1.5rem;
|
|
35
|
+
--bloom-line-height-7: 1.75rem;
|
|
36
|
+
--bloom-line-height-8: 2rem;
|
|
37
|
+
--bloom-line-height-9: 2.25rem;
|
|
38
|
+
--bloom-line-height-10: 2.5rem;
|
|
39
|
+
--bloom-line-height-none: 1;
|
|
40
|
+
--bloom-line-height-tight: 1.25;
|
|
41
|
+
--bloom-line-height-snug: 1.375;
|
|
42
|
+
--bloom-line-height-normal: 1.5;
|
|
43
|
+
--bloom-line-height-relaxed: 1.625;
|
|
44
|
+
--bloom-line-height-loose: 2;
|
|
45
|
+
}
|
|
@@ -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
|
@@ -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
|
|
@@ -423,7 +424,9 @@ const SiteHeader = (props: SiteHeaderProps) => {
|
|
|
423
424
|
|
|
424
425
|
return (
|
|
425
426
|
<header className={"site-header"}>
|
|
426
|
-
{props.languages &&
|
|
427
|
+
{props.languages && (
|
|
428
|
+
<LanguageNav ariaLabel={props.languageNavLabel} languages={props.languages} />
|
|
429
|
+
)}
|
|
427
430
|
|
|
428
431
|
<div className={`navbar-notice ${!props.noticeMobile && `navbar-notice-hide`}`}>
|
|
429
432
|
<div className="navbar-notice__text">{props.notice ?? ""}</div>
|
package/src/helpers/address.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as React from "react"
|
|
2
|
-
import Markdown from "markdown-to-jsx"
|
|
3
2
|
|
|
4
3
|
export interface Address {
|
|
5
4
|
city?: string
|
|
@@ -38,9 +37,11 @@ export const MultiLineAddress = (props: AddressProps) => {
|
|
|
38
37
|
<br />
|
|
39
38
|
</>
|
|
40
39
|
)}
|
|
41
|
-
|
|
42
|
-
<br />
|
|
43
|
-
{props.address.city}
|
|
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}
|
|
44
45
|
</>
|
|
45
46
|
)
|
|
46
47
|
}
|
|
@@ -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,28 @@
|
|
|
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* Eligibile applicants will be contacted by on a **first come first serve** basis until vacancies are filled\n\n* If you are contacted for an interview, you will need to fill out a more detailed application and provide supporting documents.",
|
|
372
379
|
"application.review.demographics.ethnicityLabel": "Which best describes your ethnicity?",
|
|
373
380
|
"application.review.demographics.ethnicityOptions.hispanicLatino": "Hispanic / Latino",
|
|
374
381
|
"application.review.demographics.ethnicityOptions.notHispanicLatino": "Not Hispanic / Latino",
|
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
|
+
}
|