@bloom-housing/ui-components 3.0.1-alpha.6 → 4.0.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.
Files changed (52) hide show
  1. package/.jest/setup-tests.js +3 -0
  2. package/CHANGELOG.md +406 -0
  3. package/index.ts +1 -8
  4. package/jest.config.js +0 -1
  5. package/package.json +4 -4
  6. package/src/actions/Button.tsx +6 -0
  7. package/src/actions/LinkButton.tsx +7 -2
  8. package/src/blocks/DashBlock.tsx +6 -1
  9. package/src/blocks/ViewItem.tsx +2 -1
  10. package/src/forms/DOBField.tsx +3 -0
  11. package/src/forms/DateField.tsx +4 -0
  12. package/src/forms/Field.tsx +3 -0
  13. package/src/forms/FieldGroup.tsx +100 -16
  14. package/src/forms/HouseholdMemberForm.tsx +2 -1
  15. package/src/forms/PhoneField.tsx +2 -1
  16. package/src/forms/Select.tsx +4 -0
  17. package/src/forms/TimeField.tsx +6 -0
  18. package/src/global/forms.scss +1 -0
  19. package/src/headers/Hero.scss +7 -0
  20. package/src/headers/Hero.tsx +3 -3
  21. package/src/headers/PageHeader.tsx +2 -2
  22. package/src/headers/SiteHeader.scss +6 -5
  23. package/src/icons/Icon.tsx +2 -1
  24. package/src/icons/Icons.tsx +7 -2
  25. package/src/locales/es.json +53 -6
  26. package/src/locales/general.json +188 -18
  27. package/src/locales/general_OLD.json +1 -1
  28. package/src/locales/missing-translations.ts +2 -0
  29. package/src/locales/tl.json +5 -0
  30. package/src/locales/vi.json +51 -5
  31. package/src/locales/zh.json +53 -7
  32. package/src/navigation/ProgressNav.tsx +5 -3
  33. package/src/notifications/AlertBox.tsx +1 -1
  34. package/src/notifications/ErrorMessage.tsx +6 -1
  35. package/src/overlays/Modal.scss +4 -1
  36. package/src/overlays/Modal.tsx +5 -6
  37. package/src/page_components/listing/AdditionalFees.tsx +2 -1
  38. package/src/page_components/listing/ListingCard.tsx +1 -1
  39. package/src/page_components/listing/listing_sidebar/GetApplication.tsx +8 -1
  40. package/src/page_components/listing/listing_sidebar/SubmitApplication.tsx +13 -3
  41. package/src/page_components/listing/listing_sidebar/Waitlist.tsx +31 -62
  42. package/src/page_components/listing/listing_sidebar/events/DownloadLotteryResults.tsx +4 -7
  43. package/src/tables/MinimalTable.tsx +2 -0
  44. package/src/tables/StandardTable.tsx +2 -1
  45. package/tsconfig.json +0 -1
  46. package/src/helpers/blankApplication.ts +0 -111
  47. package/src/helpers/localeRoute.tsx +0 -13
  48. package/src/helpers/nextjs.ts +0 -7
  49. package/src/helpers/occupancyFormatting.tsx +0 -46
  50. package/src/helpers/pdfs.ts +0 -19
  51. package/src/helpers/photos.ts +0 -19
  52. package/src/helpers/unitTypes.ts +0 -42
@@ -5,7 +5,7 @@
5
5
  "createAccount": "建立帳戶",
6
6
  "haveAnAccount": "已開立帳戶?",
7
7
  "myApplications": "我的申請",
8
- "myApplicationsSubtitle": "查看您已申請物業的抽簽日期和上市名單"
8
+ "myApplicationsSubtitle": "查看您已申請物業的抽簽日期和好屋推薦"
9
9
  },
10
10
  "application": {
11
11
  "form": {
@@ -127,10 +127,12 @@
127
127
  "assistanceUrl": "https://exygy.com/",
128
128
  "dontQualifyHeader": "很遺憾,您似乎不符合這次上市名單的申請資格。",
129
129
  "dontQualifyInfo": "如果您認為自己可能填寫錯誤,請更改資料。請注意,如果您偽造任何申請資料,您將會被取消資格。如果您填寫的資料正確無誤,我們建議您日後再回來查看,因為會有更多可供申請的物業。",
130
+ "genericSubtitle": "如果您的申請被選中,請準備提供必要文件。 ",
130
131
  "addMembers": {
131
132
  "addHouseholdMember": "+ 加入家庭成員",
132
133
  "done": "完成加入成員",
133
- "title": "請提供您家庭的資料。"
134
+ "title": "請提供您家庭的資料。",
135
+ "doubleCheck": "請再次確認每位家庭成員的資訊。"
134
136
  },
135
137
  "householdMember": "家庭成員(一人)",
136
138
  "householdMembers": "家庭成員(多人)",
@@ -142,6 +144,7 @@
142
144
  "preferredUnit": {
143
145
  "preferredUnitType": "首選單位類型",
144
146
  "title": "您對哪類單位面積感興趣?",
147
+ "subTitle": "雖然單位尺寸通常根據入住率分配,但請提供您的首選單位尺寸,以確定您在此機會的偏好或建立候補名單(僅針對此機會)",
145
148
  "optionsLabel": "請勾選所有適用的單位:",
146
149
  "options": {
147
150
  "studio": "套房",
@@ -151,6 +154,14 @@
151
154
  "fourBdrm": "3+ 間卧室"
152
155
  }
153
156
  },
157
+ "expectingChanges": {
158
+ "title": "預計家庭變化",
159
+ "question": "您預計家庭在接下來的 12 個月內可能發生什麼變化?"
160
+ },
161
+ "householdStudent": {
162
+ "title": "家人包括接近 18 歲的學生或成員",
163
+ "question": "您的家人是否有全日制學生或在 60 天內年滿 18 歲?"
164
+ },
154
165
  "member": {
155
166
  "cancelAddingThisPerson": "取消加入此人",
156
167
  "deleteThisPerson": "刪除此人",
@@ -274,7 +285,20 @@
274
285
  "americanIndianAlaskanNativeAndWhite": "美國印第安人/阿拉斯加原住民和白人",
275
286
  "asianAndWhite": "亞洲人和白人",
276
287
  "blackAfricanAmericanAndWhite": "黑人/非裔美國人和白人",
277
- "otherMutliracial": "其他/混血"
288
+ "otherMutliracial": "其他/混血",
289
+ "asian-otherAsian": "其他亞裔",
290
+ "asian-chinese": "中國人",
291
+ "asian-asianIndian": "亞洲 印度人",
292
+ "declineToRespond": "拒絕回答",
293
+ "asian-filipino": "菲律賓人",
294
+ "nativeHawaiianOtherPacificIslander-guamanianOrChamorro": "關島或查莫羅",
295
+ "asian-japanese": "日本人",
296
+ "asian-korean": "韓國人",
297
+ "nativeHawaiianOtherPacificIslander-nativeHawaiian": "夏威夷原住民",
298
+ "otherMultiracial": "其他/多種族",
299
+ "nativeHawaiianOtherPacificIslander-otherPacificIslander": "其他太平洋島民",
300
+ "nativeHawaiianOtherPacificIslander-samoan": "薩摩亞",
301
+ "asian-vietnamese": "越南人"
278
302
  },
279
303
  "genderOptions": {
280
304
  "female": "女",
@@ -292,7 +316,7 @@
292
316
  "notListed": "未列出"
293
317
  },
294
318
  "howDidYouHearOptions": {
295
- "alamedaCountyHCDWebsite": "阿拉米達縣房屋與社區發展部 (HCD) 網站",
319
+ "jurisdictionWebsite": "阿拉米達縣房屋與社區發展部 (HCD) 網站",
296
320
  "developerWebsite": "開發商網站",
297
321
  "flyer": "宣傳單",
298
322
  "emailAlert": "電郵提醒",
@@ -361,7 +385,22 @@
361
385
  "signIn": {
362
386
  "error": "您在登入時出現錯誤",
363
387
  "errorGenericMessage": "請再試一次,或聯絡支援人員尋求協助。",
388
+ "forgotPassword": "忘記密碼",
364
389
  "success": "歡迎回來,%{name}!"
390
+ },
391
+ "createAccount": {
392
+ "accountConfirmed": "您的帳戶已成功確認。",
393
+ "anEmailHasBeenSent": "本電郵已發送至 %{email}",
394
+ "confirmationInstruction": "請按一下我們發送的電子郵件內連結,並完成建立帳戶程序。",
395
+ "confirmationNeeded": "需要確認",
396
+ "resendTheEmail": "重新發送電子郵件",
397
+ "password": "密碼",
398
+ "noAccount": "沒有賬戶?",
399
+ "reEnterEmail": "重新輸入電子郵件地址",
400
+ "passwordInfo": "必須至少為 8 個字符,並且至少包含 1 個字母和至少一個數字",
401
+ "reEnterPassword": "重新輸入您的密碼",
402
+ "mustBe8Chars": "必須是 8 個字符",
403
+ "yourName": "您的姓名"
365
404
  }
366
405
  },
367
406
  "config": {
@@ -402,7 +441,7 @@
402
441
  "forGeneralQuestions": "若為一般計劃查詢,可以致電 000-000-0000 聯絡我們。",
403
442
  "giveFeedback": "提供回饋意見",
404
443
  "privacyPolicy": "隱私權政策",
405
- "copyright": "Demonstration County © 2020 • 版權所有"
444
+ "copyright": "Demonstration Jurisdiction © 2021 • 版權所有"
406
445
  },
407
446
  "housingCounselors": {
408
447
  "subtitle": "根據您的特定需求,請與您當地的房屋顧問商談。",
@@ -567,8 +606,9 @@
567
606
  },
568
607
  "nav": {
569
608
  "accountSettings": "帳戶設定",
609
+ "getFeedback": "我們希望得到您的回饋",
570
610
  "browseProperties": "瀏覽物業",
571
- "getAssistance": "尋求協助",
611
+ "getAssistance": "獲得協助",
572
612
  "listings": "好屋推薦",
573
613
  "properties": "物業",
574
614
  "applications": "申請資訊",
@@ -674,6 +714,7 @@
674
714
  "edit": "編輯",
675
715
  "email": "電子郵件",
676
716
  "emailAddressPlaceholder": "you@myemail.com",
717
+ "description": "輸入說明",
677
718
  "floor": "樓層",
678
719
  "floors": "樓層",
679
720
  "getDirections": "取得路線",
@@ -702,6 +743,7 @@
702
743
  "phone": "電話號碼",
703
744
  "phoneNumberPlaceholder": "(555) 555-5555",
704
745
  "pleaseSelectOne": "請選取一項。",
746
+ "pleaseSelectYesNo": "請選擇是或否。",
705
747
  "preferences": "優先權",
706
748
  "propertyAmenities": "物業便利設施",
707
749
  "range": "由 %{from} 至 %{to}",
@@ -737,7 +779,11 @@
737
779
  "seeRentalListings": "查看租賃部分",
738
780
  "title": "申請此地的可負擔房屋:",
739
781
  "seeMoreOpportunities": "查看更多租賃和自購住房的機會",
740
- "viewAdditionalHousing": "瀏覽其他住房機會和資源"
782
+ "viewAdditionalHousing": "瀏覽其他住房機會和資源",
783
+ "seeMoreOpportunitiesTruncated": "查看更多住屋機會及資源",
784
+ "viewAdditionalHousingTruncated": "查看機會及資源",
785
+ "signUp": "發佈新清單即收到電子郵件",
786
+ "signUpToday": "立即註冊"
741
787
  },
742
788
  "whatToExpect": {
743
789
  "label": "預期事項",
@@ -1,5 +1,4 @@
1
1
  import React from "react"
2
- import { OnClientSide } from "../helpers/nextjs"
3
2
  import "./ProgressNav.scss"
4
3
  import { t } from "../helpers/translator"
5
4
 
@@ -8,9 +7,10 @@ const ProgressNavItem = (props: {
8
7
  currentPageSection: number
9
8
  completedSections: number
10
9
  label: string
10
+ mounted: boolean
11
11
  }) => {
12
12
  let bgColor = "is-disabled"
13
- if (OnClientSide()) {
13
+ if (props.mounted) {
14
14
  if (props.section === props.currentPageSection) {
15
15
  bgColor = "is-active"
16
16
  } else if (props.completedSections >= props.section) {
@@ -39,11 +39,12 @@ const ProgressNav = (props: {
39
39
  currentPageSection: number
40
40
  completedSections: number
41
41
  labels: string[]
42
+ mounted: boolean
42
43
  }) => {
43
44
  return (
44
45
  <div>
45
46
  <h2 className="sr-only">{t("progressNav.srHeading")}</h2>
46
- <ul className={!OnClientSide() ? "invisible" : "progress-nav"}>
47
+ <ul className={!props.mounted ? "invisible" : "progress-nav"}>
47
48
  {props.labels.map((label, i) => (
48
49
  <ProgressNavItem
49
50
  key={label}
@@ -52,6 +53,7 @@ const ProgressNav = (props: {
52
53
  currentPageSection={props.currentPageSection}
53
54
  completedSections={props.completedSections}
54
55
  label={label}
56
+ mounted={props.mounted}
55
57
  />
56
58
  ))}
57
59
  </ul>
@@ -70,7 +70,7 @@ const AlertBox = (props: AlertBoxProps) => {
70
70
  }
71
71
 
72
72
  return showing ? (
73
- <div className={classNames} role="alert">
73
+ <div className={classNames} role="alert" data-test-id={"alert-box"}>
74
74
  {innerSection}
75
75
  </div>
76
76
  ) : null
@@ -3,7 +3,12 @@ import React from "react"
3
3
  const ErrorMessage = (props: { id?: string; error?: boolean; children?: React.ReactNode }) => {
4
4
  if (props.error) {
5
5
  return (
6
- <span id={props.id} className="error-message" aria-live="assertive">
6
+ <span
7
+ id={props.id}
8
+ className="error-message"
9
+ aria-live="assertive"
10
+ data-test-id={"error-message"}
11
+ >
7
12
  {props.children}
8
13
  </span>
9
14
  )
@@ -8,7 +8,10 @@
8
8
  @apply bg-white;
9
9
  @apply rounded-md;
10
10
  @apply shadow-md;
11
- min-width: 32rem;
11
+
12
+ @screen md {
13
+ min-width: 32rem;
14
+ }
12
15
  }
13
16
 
14
17
  // Content containers
@@ -19,12 +19,11 @@ const ModalHeader = (props: { title: string }) => (
19
19
 
20
20
  const ModalFooter = (props: { actions: React.ReactNode[] }) => (
21
21
  <footer className="modal__footer bg-primary-lighter" data-testid="footer">
22
- <GridSection columns={4} reverse={true} tightSpacing={true}>
23
- {props.actions &&
24
- props.actions.map((action: React.ReactNode, index: number) => (
25
- <GridCell key={index}>{action}</GridCell>
26
- ))}
27
- </GridSection>
22
+ <div className="flex flex-row-reverse gap-5">
23
+ {props.actions.map((action: React.ReactNode, index: number) => (
24
+ <div key={index}>{action}</div>
25
+ ))}
26
+ </div>
28
27
  </footer>
29
28
  )
30
29
 
@@ -6,6 +6,7 @@ export interface AdditionalFeesProps {
6
6
  depositMax?: string
7
7
  applicationFee?: string
8
8
  costsNotIncluded?: string
9
+ depositHelperText?: string
9
10
  }
10
11
 
11
12
  const AdditionalFees = (props: AdditionalFeesProps) => {
@@ -37,7 +38,7 @@ const AdditionalFees = (props: AdditionalFeesProps) => {
37
38
  <div className="info-card__column">
38
39
  <div className="text-base">{t("t.deposit")}</div>
39
40
  <div className="text-xl font-bold">{getDeposit()}</div>
40
- <div>{t("listings.depositOrMonthsRent")}</div>
41
+ {props.depositHelperText && <div>{props.depositHelperText}</div>}
41
42
  </div>
42
43
  )}
43
44
  </div>
@@ -28,7 +28,7 @@ const ListingCard = (props: ListingCardProps) => {
28
28
  const { imageCardProps, tableProps, detailsLinkClass, tableHeaderProps } = props
29
29
 
30
30
  return (
31
- <article className="listings-row">
31
+ <article className="listings-row" data-test-id={"listing-card-component"}>
32
32
  <div className="listings-row_figure">
33
33
  <ImageCard {...imageCardProps} />
34
34
  </div>
@@ -7,6 +7,7 @@ import { Address } from "../../../helpers/address"
7
7
  import { SidebarAddress } from "./SidebarAddress"
8
8
  import { NumberedHeader } from "./NumberedHeader"
9
9
  import { OrDivider } from "./OrDivider"
10
+ import { ListingStatus } from "@bloom-housing/backend-core/types"
10
11
 
11
12
  export interface PaperApplication {
12
13
  fileURL: string
@@ -24,12 +25,17 @@ export interface ApplicationsProps {
24
25
  applicationPickUpAddressOfficeHours?: string
25
26
  applicationPickUpAddress?: Address
26
27
  preview?: boolean
28
+ listingStatus?: ListingStatus
27
29
  }
28
30
 
29
31
  const GetApplication = (props: ApplicationsProps) => {
30
32
  const [showDownload, setShowDownload] = useState(false)
31
33
  const toggleDownload = () => setShowDownload(!showDownload)
32
34
 
35
+ if (props.listingStatus === ListingStatus.closed) {
36
+ return null
37
+ }
38
+
33
39
  return (
34
40
  <section className="aside-block">
35
41
  <h2 className="text-caps-underline">{t("listings.apply.howToApply")}</h2>
@@ -43,7 +49,7 @@ const GetApplication = (props: ApplicationsProps) => {
43
49
  {props.applicationsOpen && props.onlineApplicationURL && (
44
50
  <>
45
51
  {props.preview ? (
46
- <Button disabled className="w-full mb-2">
52
+ <Button disabled className="w-full mb-2" data-test-id={"listing-view-apply-button"}>
47
53
  {t("listings.apply.applyOnline")}
48
54
  </Button>
49
55
  ) : (
@@ -51,6 +57,7 @@ const GetApplication = (props: ApplicationsProps) => {
51
57
  styleType={AppearanceStyleType.primary}
52
58
  className="w-full mb-2"
53
59
  href={props.onlineApplicationURL}
60
+ dataTestId={"listing-view-apply-button"}
54
61
  >
55
62
  {t("listings.apply.applyOnline")}
56
63
  </LinkButton>
@@ -4,6 +4,7 @@ import { Address } from "../../../helpers/address"
4
4
  import { SidebarAddress } from "./SidebarAddress"
5
5
  import { NumberedHeader } from "./NumberedHeader"
6
6
  import { OrDivider } from "./OrDivider"
7
+ import { ListingStatus } from "@bloom-housing/backend-core/types"
7
8
 
8
9
  export interface PostmarkedApplication {
9
10
  postmarkedApplicationsReceivedByDate: string
@@ -17,19 +18,28 @@ export interface ApplicationAddressesProps {
17
18
  applicationDropOffAddressOfficeHours?: string
18
19
  applicationOrganization?: string
19
20
  postmarkedApplicationData?: PostmarkedApplication
21
+ listingStatus?: ListingStatus
20
22
  }
21
23
 
22
24
  const SubmitApplication = (props: ApplicationAddressesProps) => {
25
+ if (props.listingStatus === ListingStatus.closed) {
26
+ return null
27
+ }
28
+
23
29
  return (
24
30
  <>
25
- {(props.applicationMailingAddress || props.applicationDropOffAddress) && (
31
+ {(props.applicationMailingAddress ||
32
+ props.applicationDropOffAddress ||
33
+ props.postmarkedApplicationData) && (
26
34
  <section className="aside-block is-tinted bg-gray-100">
27
35
  <NumberedHeader num={2} text={t("listings.apply.submitAPaperApplication")} />
28
- {props.applicationMailingAddress && (
36
+ {(props.applicationMailingAddress || props.postmarkedApplicationData) && (
29
37
  <>
30
38
  <h3 className="text-caps-tiny">{t("listings.apply.sendByUsMail")}</h3>
31
39
  <p className="text-gray-700">{props.applicationOrganization}</p>
32
- <SidebarAddress address={props.applicationMailingAddress} />
40
+ {props.applicationMailingAddress && (
41
+ <SidebarAddress address={props.applicationMailingAddress} />
42
+ )}
33
43
  <p className="mt-4 text-tiny text-gray-750">
34
44
  {props.postmarkedApplicationData?.postmarkedApplicationsReceivedByDate
35
45
  ? t("listings.apply.postmarkedApplicationsMustBeReceivedByDate", {
@@ -1,77 +1,46 @@
1
1
  import * as React from "react"
2
2
  import { t } from "../../../helpers/translator"
3
3
 
4
- const WaitlistItem = (props: { className?: string; value: number; text: string }) => {
5
- return props.value ? (
6
- <li className={`uppercase text-gray-800 text-tiny ${props.className}`}>
7
- <span className="text-right w-12 inline-block pr-2">{props.value}</span>
8
- <span>{props.text}</span>
9
- </li>
10
- ) : null
11
- }
12
-
13
4
  export interface WaitlistProps {
14
5
  isWaitlistOpen: boolean
15
- waitlistMaxSize: number
16
- waitlistCurrentSize: number
17
- waitlistOpenSpots: number
18
- unitsAvailable: number
6
+ waitlistMaxSize?: number | null
7
+ waitlistCurrentSize?: number | null
8
+ waitlistOpenSpots?: number | null
19
9
  }
20
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
+
21
18
  const Waitlist = (props: WaitlistProps) => {
22
- let header, subheader, waitlistItems
23
- if (!props.isWaitlistOpen && !props.waitlistCurrentSize) return <></>
24
- if (props.unitsAvailable && props.unitsAvailable > 0 && props.isWaitlistOpen) {
25
- header = t("listings.waitlist.unitsAndWaitlist")
26
- subheader = t("listings.waitlist.submitAnApplication")
27
- waitlistItems = (
28
- <>
29
- <WaitlistItem
30
- value={props.unitsAvailable}
31
- text={t("listings.availableUnits")}
32
- className={"font-semibold"}
33
- />
34
- {props.waitlistOpenSpots && (
35
- <WaitlistItem
36
- value={props.waitlistOpenSpots}
37
- text={t("listings.waitlist.openSlots")}
38
- className={"font-semibold"}
39
- />
40
- )}
41
- </>
42
- )
43
- } else {
44
- if (props.isWaitlistOpen) {
45
- header = t("listings.waitlist.isOpen")
46
- subheader = t("listings.waitlist.submitForWaitlist")
47
- } else {
48
- header = t("listings.waitlist.closed")
49
- subheader = null
50
- }
51
- waitlistItems = (
52
- <>
53
- <WaitlistItem
54
- value={props.waitlistCurrentSize || 0}
55
- text={t("listings.waitlist.currentSize")}
56
- />
57
- {props.waitlistOpenSpots && (
58
- <WaitlistItem
59
- value={props.waitlistOpenSpots}
60
- text={t("listings.waitlist.openSlots")}
61
- className={"font-semibold"}
62
- />
63
- )}
64
- <WaitlistItem value={props.waitlistMaxSize || 0} text={t("listings.waitlist.finalSize")} />
65
- </>
66
- )
67
- }
19
+ if (!props.isWaitlistOpen) return <></>
68
20
 
69
21
  return (
70
22
  <section className="aside-block is-tinted">
71
- <h4 className="text-caps-tiny">{header}</h4>
23
+ <h4 className="text-caps-tiny">{t("listings.waitlist.unitsAndWaitlist")}</h4>
72
24
  <div>
73
- {subheader && <p className="text-tiny text-gray-800 pb-3">{subheader}</p>}
74
- {<ul>{waitlistItems}</ul>}
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>
75
44
  </div>
76
45
  </section>
77
46
  )
@@ -1,14 +1,11 @@
1
1
  import * as React from "react"
2
- import { ListingEvent, ListingEventType } from "@bloom-housing/backend-core/types"
2
+ import { ListingEvent } from "@bloom-housing/backend-core/types"
3
3
  import { t } from "../../../../helpers/translator"
4
- import { pdfUrlFromListingEvents } from "../../../../helpers/pdfs"
5
4
  import moment from "moment"
6
5
 
7
- const DownloadLotteryResults = (props: { event: ListingEvent; cloudName: string }) => {
8
- const { event, cloudName } = props
9
- const eventUrl = event
10
- ? pdfUrlFromListingEvents([event], ListingEventType.lotteryResults, cloudName)
11
- : null
6
+ const DownloadLotteryResults = (props: { event: ListingEvent; pdfUrl: string }) => {
7
+ const { event, pdfUrl } = props
8
+ const eventUrl = event ? pdfUrl : null
12
9
  return (
13
10
  <>
14
11
  {eventUrl && (
@@ -11,6 +11,7 @@ export interface MinimalTableProps {
11
11
  responsiveCollapse?: boolean
12
12
  className?: string
13
13
  cellClassName?: string
14
+ id?: string
14
15
  }
15
16
 
16
17
  const MinimalTable = (props: MinimalTableProps) => {
@@ -26,6 +27,7 @@ const MinimalTable = (props: MinimalTableProps) => {
26
27
  tableClassName={tableClasses.join(" ")}
27
28
  cellClassName={`${props.cellClassName ? props.cellClassName : `px-5 py-3`}`}
28
29
  responsiveCollapse={props.responsiveCollapse}
30
+ id={props.id}
29
31
  />
30
32
  )
31
33
  }
@@ -51,6 +51,7 @@ export interface StandardTableProps {
51
51
  cellClassName?: string
52
52
  responsiveCollapse?: boolean
53
53
  translateData?: boolean
54
+ id?: string
54
55
  }
55
56
 
56
57
  export type StandardTableData = Record<string, React.ReactNode>[] | undefined
@@ -204,7 +205,7 @@ export const StandardTable = (props: StandardTableProps) => {
204
205
 
205
206
  return (
206
207
  <div style={{ overflowX: "auto" }}>
207
- <table className={tableClasses.join(" ")}>
208
+ <table id={props.id} className={tableClasses.join(" ")}>
208
209
  <thead>
209
210
  <tr>{headerLabels}</tr>
210
211
  </thead>
package/tsconfig.json CHANGED
@@ -2,7 +2,6 @@
2
2
  "extends": "../tsconfig.json" /* TODO: is this worth connecting? */,
3
3
  "compilerOptions": {
4
4
  "outDir": "build/lib",
5
- // "module": "es2015",
6
5
  "module": "esnext",
7
6
  "esModuleInterop": true,
8
7
  "target": "es5",
@@ -1,111 +0,0 @@
1
- import {
2
- ApplicationStatus,
3
- ApplicationSubmissionType,
4
- Language,
5
- ApplicationPreference,
6
- } from "@bloom-housing/backend-core/types"
7
-
8
- export const blankApplication = () => {
9
- return {
10
- loaded: false,
11
- autofilled: false,
12
- completedSections: 0,
13
- submissionType: ApplicationSubmissionType.electronical,
14
- language: Language.en,
15
- acceptedTerms: false,
16
- status: ApplicationStatus.submitted,
17
- applicant: {
18
- orderId: undefined,
19
- firstName: "",
20
- middleName: "",
21
- lastName: "",
22
- birthMonth: "",
23
- birthDay: "",
24
- birthYear: "",
25
- emailAddress: null,
26
- noEmail: false,
27
- phoneNumber: "",
28
- phoneNumberType: "",
29
- noPhone: false,
30
- workInRegion: null,
31
- address: {
32
- street: "",
33
- street2: "",
34
- city: "",
35
- state: "",
36
- zipCode: "",
37
- county: "",
38
- latitude: null,
39
- longitude: null,
40
- },
41
- workAddress: {
42
- street: "",
43
- street2: "",
44
- city: "",
45
- state: "",
46
- zipCode: "",
47
- county: "",
48
- latitude: null,
49
- longitude: null,
50
- },
51
- },
52
- additionalPhone: false,
53
- additionalPhoneNumber: "",
54
- additionalPhoneNumberType: "",
55
- contactPreferences: [],
56
- householdSize: 0,
57
- housingStatus: "",
58
- sendMailToMailingAddress: false,
59
- mailingAddress: {
60
- street: "",
61
- street2: "",
62
- city: "",
63
- state: "",
64
- zipCode: "",
65
- },
66
- alternateAddress: {
67
- street: "",
68
- street2: "",
69
- city: "",
70
- state: "",
71
- zipCode: "",
72
- },
73
- alternateContact: {
74
- type: "",
75
- otherType: "",
76
- firstName: "",
77
- lastName: "",
78
- agency: "",
79
- phoneNumber: "",
80
- emailAddress: null,
81
- mailingAddress: {
82
- street: "",
83
- city: "",
84
- state: "",
85
- zipCode: "",
86
- },
87
- },
88
- accessibility: {
89
- mobility: null,
90
- vision: null,
91
- hearing: null,
92
- },
93
- householdExpectingChanges: null,
94
- householdStudent: null,
95
- incomeVouchers: null,
96
- income: null,
97
- incomePeriod: null,
98
- householdMembers: [],
99
- preferredUnit: [],
100
- demographics: {
101
- ethnicity: "",
102
- race: "",
103
- gender: "",
104
- sexualOrientation: "",
105
- howDidYouHear: [],
106
- },
107
- preferences: [] as ApplicationPreference[],
108
- confirmationCode: "",
109
- id: "",
110
- }
111
- }
@@ -1,13 +0,0 @@
1
- import { t } from "./translator"
2
-
3
- export const lRoute = (routeString: string) => {
4
- if (routeString.startsWith("http")) return routeString
5
-
6
- let routePrefix = t("config.routePrefix")
7
- if (routePrefix == "config.routePrefix" || routePrefix == "") {
8
- routePrefix = "" // no prefix needed for default routes
9
- } else {
10
- routePrefix = "/" + routePrefix
11
- }
12
- return `${routePrefix}${routeString}`
13
- }
@@ -1,7 +0,0 @@
1
- import { useEffect, useState } from "react"
2
-
3
- export const OnClientSide = () => {
4
- const [mounted, setMounted] = useState(false)
5
- useEffect(() => setMounted(true), [])
6
- return mounted
7
- }