From 4a07ae2835084c95b4f9b6dedcd7bcabd2b9c593 Mon Sep 17 00:00:00 2001 From: cade-exygy <131277283+cade-exygy@users.noreply.github.com> Date: Fri, 26 Jan 2024 13:20:10 -0600 Subject: [PATCH 01/20] feat: 3761/direct to sign in (#3816) * feat: check if user is logged in * fix: clean up logs * fix: remove unneeded prop * fix: sign in before submit application test * fix: add feature toggle * fix: sign in before submitApplication tests * fix: fix test * fix: add feature flag to circleCI * fix: remove toggle * refactor: move redirect logic to ListingView --- .../components/listing/GetApplication.test.tsx | 4 ++++ .../src/components/listing/GetApplication.tsx | 4 ++++ .../public/src/components/listing/ListingView.tsx | 15 ++++++++++++--- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/sites/public/__tests__/components/listing/GetApplication.test.tsx b/sites/public/__tests__/components/listing/GetApplication.test.tsx index 098e9657df..1b9d72e65e 100644 --- a/sites/public/__tests__/components/listing/GetApplication.test.tsx +++ b/sites/public/__tests__/components/listing/GetApplication.test.tsx @@ -27,6 +27,7 @@ describe("", () => { }} preview={false} listingName={"Listing name"} + listingId="123" /> ) expect(getByText("How to Apply")).toBeTruthy() @@ -57,6 +58,7 @@ describe("", () => { }} preview={false} listingName={"Listing name"} + listingId="123" /> ) expect(queryByTestId("get-application-section")).toBeNull() @@ -83,6 +85,7 @@ describe("", () => { }} preview={true} listingName={"Listing name"} + listingId="123" /> ) expect(getByText("Apply Online").closest("button")?.disabled).toBe(true) @@ -109,6 +112,7 @@ describe("", () => { }} preview={false} listingName={"Listing name"} + listingId="123" /> ) expect(queryByText("Apply Online")).toBe(null) diff --git a/sites/public/src/components/listing/GetApplication.tsx b/sites/public/src/components/listing/GetApplication.tsx index f9778a8674..ce5e866822 100644 --- a/sites/public/src/components/listing/GetApplication.tsx +++ b/sites/public/src/components/listing/GetApplication.tsx @@ -32,6 +32,8 @@ export interface ApplicationsProps { applicationsOpenDate?: string /** The name of the listing */ listingName: string + /** The id of the listing */ + listingId: string /** The URL for an online applications */ onlineApplicationURL?: string /** Any number of paper application objects, including their URL and language */ @@ -40,6 +42,8 @@ export interface ApplicationsProps { paperMethod?: boolean /** The date mailed applications must be received by */ postmarkedApplicationsReceivedByDate?: string + /** Informs whether or not to hide actionable application buttons */ + listingStatus?: string /** Whether or not to hide actionable application buttons */ preview?: boolean strings?: { diff --git a/sites/public/src/components/listing/ListingView.tsx b/sites/public/src/components/listing/ListingView.tsx index fe7c28f5f0..ce5fef06d2 100644 --- a/sites/public/src/components/listing/ListingView.tsx +++ b/sites/public/src/components/listing/ListingView.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React, { useContext } from "react" import ReactDOMServer from "react-dom/server" import Markdown from "markdown-to-jsx" import { @@ -35,7 +35,6 @@ import { ExpandableSection, SiteAlert, StandardTable, - GroupedTable, ImageCard, Icon, } from "@bloom-housing/ui-components" @@ -52,6 +51,7 @@ import { getSummariesTable, getPdfUrlFromAsset, IMAGE_FALLBACK_URL, + AuthContext, } from "@bloom-housing/shared-helpers" import dayjs from "dayjs" import { ErrorPage } from "../../pages/_error" @@ -79,6 +79,7 @@ interface ListingProps { } export const ListingView = (props: ListingProps) => { + const { initialStateLoaded, profile } = useContext(AuthContext) let buildingSelectionCriteria, preferencesSection const { listing } = props const { @@ -353,10 +354,17 @@ export const ListingView = (props: ListingProps) => { return date ? dayjs(date).format(format) : null } + const redirectIfSignedOut = () => + process.env.showMandatedAccounts && initialStateLoaded && !profile + const applySidebar = () => ( <> { applicationPickUpAddress={getAddress(listing.applicationPickUpAddressType, "pickUp")} preview={props.preview} listingName={listing.name} + listingId={listing.id} /> {!( listing.status === ListingStatus.closed || From e50998561c084e9b6e925cbc89150fd16a5c440e Mon Sep 17 00:00:00 2001 From: ColinBuyck <53269332+ColinBuyck@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:22:25 -0800 Subject: [PATCH 02/20] feat: 422/updated account theming (#3791) * fix: rough draft refactoring * fix: wip seeds card * fix: wip account updates * fix: account card styling * fix: wip status item styling * fix: edit screen adjustments * fix: css matched app view * fix: testing fixes * fix: getById chnage * fix: add plural copy fix * fix: json update * fix: remove tailwind * fix: font weight touches * fix: mantain translations * fix: reorganizing files * fix: svg updates * fix: current pswd translations * fix: unused css * fix: width needed * fix: css and heading updates * fix: account card updates * fix: partial new icon approach * fix: final tweaks * fix: no border figma matching --- shared-helpers/src/locales/general.json | 4 + .../cypress/e2e/pages/my-applications.spec.ts | 2 +- .../account/AccountCard.module.scss | 24 ++ .../src/components/account/AccountCard.tsx | 49 +++ .../components/account/StatusItem.module.scss | 148 ++++----- .../src/components/account/StatusItem.tsx | 59 ++-- .../src/components/shared/CustomIconMap.tsx | 8 + .../src/components/shared/CustomIcons.tsx | 61 ++++ .../src/pages/account/account.module.scss | 26 ++ .../public/src/pages/account/applications.tsx | 49 +-- sites/public/src/pages/account/dashboard.tsx | 78 ++--- sites/public/src/pages/account/edit.tsx | 286 +++++++++--------- 12 files changed, 477 insertions(+), 317 deletions(-) create mode 100644 sites/public/src/components/account/AccountCard.module.scss create mode 100644 sites/public/src/components/account/AccountCard.tsx create mode 100644 sites/public/src/components/shared/CustomIconMap.tsx create mode 100644 sites/public/src/components/shared/CustomIcons.tsx create mode 100644 sites/public/src/pages/account/account.module.scss diff --git a/shared-helpers/src/locales/general.json b/shared-helpers/src/locales/general.json index 38dc8ef53f..324fc40f45 100644 --- a/shared-helpers/src/locales/general.json +++ b/shared-helpers/src/locales/general.json @@ -1,15 +1,18 @@ { "account.accountSettings": "Account Settings", "account.accountSettingsSubtitle": "Account Settings, email and password", + "account.accountSettingsUpdate": "Update account settings", "account.application.confirmation": "Confirmation", "account.application.error": "Error", "account.application.noAccessError": "You are unauthorized to view this application", "account.application.noApplicationError": "No application with that ID exists", "account.application.return": "Return to applications", + "account.application.iconTitle": "application with checkmarks", "account.createAccount": "Create Account", "account.errorFetchingApplications": "Error fetching applications", "account.haveAnAccount": "Already have an account?", "account.myApplications": "My Applications", + "account.viewApplications": "View applications", "account.myApplicationsSubtitle": "See lottery dates and listings for properties for which you've applied", "account.noApplications": "It looks like you haven't applied to any listings yet.", "account.settings.alerts.currentPassword": "Invalid current password. Please try again.", @@ -28,6 +31,7 @@ "account.settings.placeholders.month": "MM", "account.settings.placeholders.year": "YYYY", "account.settings.update": "Update", + "account.settings.iconTitle": "generic user", "application.ada.hearing": "For Hearing Impairments", "application.ada.label": "ADA Accessible Units", "application.ada.mobility": "For Mobility Impairments", diff --git a/sites/public/cypress/e2e/pages/my-applications.spec.ts b/sites/public/cypress/e2e/pages/my-applications.spec.ts index e4bfb0016d..4554dea414 100644 --- a/sites/public/cypress/e2e/pages/my-applications.spec.ts +++ b/sites/public/cypress/e2e/pages/my-applications.spec.ts @@ -4,7 +4,7 @@ describe("My applications page", function () { cy.visit("/sign-in") cy.signIn() cy.url().should("include", "/account/dashboard") - cy.getByTestId("account-dashboard-applications").click() + cy.getByID("account-dashboard-applications").click() cy.location("pathname").should("include", "/account/applications") cy.signOut() }) diff --git a/sites/public/src/components/account/AccountCard.module.scss b/sites/public/src/components/account/AccountCard.module.scss new file mode 100644 index 0000000000..7cfd3921ac --- /dev/null +++ b/sites/public/src/components/account/AccountCard.module.scss @@ -0,0 +1,24 @@ +.account-card { + --card-header-padding-inline-desktop: var(--seeds-s12); + --card-header-padding-inline-mobile: var(--seeds-s4); + --card-content-padding-inline-mobile: var(--seeds-s4); + --card-border-width: 0rem; + width: 100%; + @media (max-width: theme("screens.sm")) { + --card-spacing-lg: var(--seeds-s6); + --card-border-radius: 0rem; + } +} + +.acccount-card-icon { + margin-bottom: var(--seeds-s3); +} + +.account-card-heading-group { + --subheading-margin: var(--seeds-s3); + --heading-margin: var(--seeds-s3); +} + +.account-card-heading { + margin-top: var(--seeds-s3); +} diff --git a/sites/public/src/components/account/AccountCard.tsx b/sites/public/src/components/account/AccountCard.tsx new file mode 100644 index 0000000000..588ac4f002 --- /dev/null +++ b/sites/public/src/components/account/AccountCard.tsx @@ -0,0 +1,49 @@ +import { Heading, HeadingGroup, Icon } from "@bloom-housing/ui-seeds" +import Card from "@bloom-housing/ui-seeds/src/blocks/Card" +import React from "react" +import styles from "./AccountCard.module.scss" +import { CustomIconMap, CustomIconType } from "../shared/CustomIconMap" + +interface AccountCardProps { + iconSymbol: CustomIconType + title: string + subtitle?: string + children: React.ReactElement + id?: string + divider?: "flush" | "inset" + headingPriority?: 1 | 2 | 3 | 4 | 5 | 6 + className?: string +} + +const AccountCard = (props: AccountCardProps) => { + const classNames = [styles["account-card"]] + if (props.className) classNames.push(props.className) + + const customIcon = CustomIconMap[props.iconSymbol] + + return ( + + + + {customIcon} + + {props.subtitle ? ( + + ) : ( + + {props.title} + + )} + + {props.children} + + ) +} + +export { AccountCard as default, AccountCard } diff --git a/sites/public/src/components/account/StatusItem.module.scss b/sites/public/src/components/account/StatusItem.module.scss index 86f62c980d..8abc78ad41 100644 --- a/sites/public/src/components/account/StatusItem.module.scss +++ b/sites/public/src/components/account/StatusItem.module.scss @@ -1,132 +1,92 @@ .status-item { - @apply relative; - @apply text-gray-800; - @apply border-b; - @apply border-solid; - @apply border-gray-450; - @apply bg-primary-lighter; - - &:last-of-type { - @apply border-b-0; - } -} - -.status-item__inner { - @apply p-4; + position: relative; + padding: var(--seeds-s4); + background-color: var(--seeds-color-primary-lighter); + color: var(--seeds-gray-800); + border-bottom-width: 0.0625rem; + border-style: solid; + border-color: var(--seeds-color-gray-450); } .status-item__header { - @apply pb-2; - - @screen md { - @apply flex; - @apply mb-4; - @apply justify-between; - @apply border-b; - @apply border-solid; - @apply border-gray-450; + display: flex; + padding-bottom: var(--seeds-s4); + justify-content: space-between; + border-bottom-width: 0.0625rem; + border-style: solid; + border-color: var(--seeds-color-gray-450); + margin-bottom: var(seeds-s4); + @media (max-width: theme("screens.md")) { + padding-bottom: var(--seeds-s2); + display: block; } } .status-item__title { - @apply text-xl; - @apply font-alt-sans; - @apply tracking-wider; - @apply mb-0; - @apply uppercase; + font-size: var(--seeds-font-size-lg); + margin-bottom: 0; } .status-item__due { - @screen md { - @apply text-right; - @apply self-center; + text-align: right; + align-self: center; + font-size: var(--seeds-font-size-sm); + @media (max-width: theme("screens.md")) { + text-align: left; + padding-top: var(--seeds-s2_5); } } .status-item__content { - @screen md { - @apply flex; - @apply justify-between; + display: flex; + justify-content: space-between; + padding-top: var(--seeds-s4); + @media (max-width: theme("screens.md")) { + display: grid; } } .status-confirmation__number { - @apply pt-4; -} - -.status-item__details { - @apply text-center; - @screen md { - @apply text-left; - } + padding-top: var(--seeds-s4); } .status-item__action { - @apply text-center; - @apply pt-4; - @apply mb-4; + padding-top: 0; + text-align: right; - @screen md { - @apply pt-0; - @apply text-right; + @media (max-width: theme("screens.md")) { + text-align: center; + padding-top: var(seeds-s4); + margin-bottom: var(--seeds-s4); } } .status-item__footer { - @apply text-center; - - @screen md { - @apply flex; - @apply justify-between; - @apply text-left; - @apply gap-4; - } -} - -.status-item__links { - @apply pb-4; - - @screen md { - @apply pb-0; - } -} - -.status-item__meta { - @apply mt-4; - - @screen md { - @apply text-right; - @apply mt-0; + display: flex; + gap: var(--seeds-s4); + flex-direction: row; + justify-content: flex-start; + padding-top: var(--seeds-s4); + width: fit-content; + @media (max-width: theme("screens.md")) { + flex-direction: column; } } .status-item__status { - @apply pb-4; -} - -.status-item__label { - @apply relative; -} - -.status-item__date { - @apply text-xs; -} - -.status-item__address { - @apply mb-4; + padding-block: 0; + font-size: var(--seeds-font-size-sm); + @media (max-width: theme("screens.md")) { + padding-block: var(--seeds-s4); + } } .status-item__confirm-text { - @apply text-sm; - @apply mb-4; + font-size: var(--seeds-font-size-sm); + margin-bottom: var(--seeds-s4); } .status-item__confirm-number { - @apply text-xl; -} - -.status-item__address { - @screen md { - @apply text-left; - } + font-size: var(--seeds-font-size-lg); + padding-top: var(--seeds-s2); } diff --git a/sites/public/src/components/account/StatusItem.tsx b/sites/public/src/components/account/StatusItem.tsx index 570b675818..94f32ad023 100644 --- a/sites/public/src/components/account/StatusItem.tsx +++ b/sites/public/src/components/account/StatusItem.tsx @@ -1,7 +1,8 @@ import React from "react" import { t } from "@bloom-housing/ui-components" -import { Button, Link } from "@bloom-housing/ui-seeds" +import { Button, Card, Tag } from "@bloom-housing/ui-seeds" import styles from "./StatusItem.module.scss" +import accountStyles from "../../pages/account/account.module.scss" interface StatusItemProps { applicationDueDate?: string @@ -11,7 +12,7 @@ interface StatusItemProps { listingName: string listingURL: string strings?: { - applicationDeadline?: string + applicationsDeadline?: string edited?: string seeListing?: string status?: string @@ -23,20 +24,22 @@ interface StatusItemProps { const StatusItem = (props: StatusItemProps) => { return ( -
-
+ +

{props.listingName}

- {props.applicationDueDate && ( -

- {props.strings?.applicationDeadline ?? t("listings.applicationDeadline")}:{" "} - {props.applicationDueDate} -

- )} +

+ {props.strings?.status ?? t("application.status")}:{" "} + + {props.strings?.submittedStatus ?? t("application.statuses.submitted")} + +

-
+
{props.confirmationNumber && ( <> @@ -51,31 +54,29 @@ const StatusItem = (props: StatusItemProps) => {
-

- - {props.strings?.status ?? t("application.status")}:{" "} - {props.strings?.submittedStatus ?? t("application.statuses.submitted")} - -

- + {props.applicationDueDate && ( +

+ {props.strings?.applicationsDeadline ?? t("listings.applicationDeadline")}:{" "} + {props.applicationDueDate} +

+ )}
-
- {props.strings?.seeListing ?? t("t.seeListing")} +
+
- -
-

- {props.strings?.edited ?? t("application.edited")}: {props.applicationUpdatedAt} -

+
+
-
-
+ + ) } diff --git a/sites/public/src/components/shared/CustomIconMap.tsx b/sites/public/src/components/shared/CustomIconMap.tsx new file mode 100644 index 0000000000..a31df30e4f --- /dev/null +++ b/sites/public/src/components/shared/CustomIconMap.tsx @@ -0,0 +1,8 @@ +import { Application, Profile } from "./CustomIcons" + +export const CustomIconMap = { + application: Application, + profile: Profile, +} + +export type CustomIconType = keyof typeof CustomIconMap diff --git a/sites/public/src/components/shared/CustomIcons.tsx b/sites/public/src/components/shared/CustomIcons.tsx new file mode 100644 index 0000000000..7d4172a4a7 --- /dev/null +++ b/sites/public/src/components/shared/CustomIcons.tsx @@ -0,0 +1,61 @@ +import { t } from "@bloom-housing/ui-components" + +export const Application = ( + + {t("account.application.iconTitle")} + + + + + + + + + +) + +export const Profile = ( + + {t("account.settings.iconTitle")} + + + +) diff --git a/sites/public/src/pages/account/account.module.scss b/sites/public/src/pages/account/account.module.scss new file mode 100644 index 0000000000..79e3b2761b --- /dev/null +++ b/sites/public/src/pages/account/account.module.scss @@ -0,0 +1,26 @@ +.account-card-container { + padding-inline: var(--seeds-s6); + @media (max-width: theme("screens.sm")) { + padding-inline: 0rem; + padding-block: var(--seeds-s4); + } +} + +.account-card-section { + @media (min-width: theme("screens.sm")) { + --card-content-padding-inline: var(--seeds-s12); + } +} + +.application-card-section { + --card-content-padding-block: var(--seeds-s6); +} + +.account-settings-label { + font-size: var(--seeds-font-size-sm); + font-weight: var(--seeds-font-weight-bold); +} + +.application-no-results { + padding-bottom: var(--seeds-s4); +} diff --git a/sites/public/src/pages/account/applications.tsx b/sites/public/src/pages/account/applications.tsx index ccd41ec119..8d4fd365c1 100644 --- a/sites/public/src/pages/account/applications.tsx +++ b/sites/public/src/pages/account/applications.tsx @@ -1,12 +1,15 @@ import React, { useEffect, useState, Fragment, useContext } from "react" import Head from "next/head" -import { DashBlock, DashBlocks, HeaderBadge, t, LoadingOverlay } from "@bloom-housing/ui-components" -import { Button } from "@bloom-housing/ui-seeds" +import { t, LoadingOverlay } from "@bloom-housing/ui-components" +import { Button, Card, Heading } from "@bloom-housing/ui-seeds" import { PageView, pushGtmEvent, AuthContext, RequireLogin } from "@bloom-housing/shared-helpers" import Layout from "../../layouts/application" import { StatusItemWrapper, AppWithListing } from "./StatusItemWrapper" import { MetaTags } from "../../components/shared/MetaTags" import { UserStatus } from "../../lib/constants" +import { AccountCard } from "../../components/account/AccountCard" + +import styles from "../../pages/account/account.module.scss" const Applications = () => { const { applicationsService, listingsService, profile } = useContext(AuthContext) @@ -57,17 +60,23 @@ const Applications = () => { }, [applications, listLoading, listingsService]) const noApplicationsSection = () => { - return error ? ( -
-

{`${t("account.errorFetchingApplications")}`}

-
- ) : ( -
-

{t("account.noApplications")}

- -
+ return ( + + {error ? ( + {`${t("account.errorFetchingApplications")}`} + ) : ( + <> + + {t("account.noApplications")} + + + + )} + ) } return ( @@ -79,8 +88,13 @@ const Applications = () => {
- - }> + + <> {applications?.map((application, index) => { @@ -88,9 +102,10 @@ const Applications = () => { })} + {!applications && !loading && noApplicationsSection()} - - + +
diff --git a/sites/public/src/pages/account/dashboard.tsx b/sites/public/src/pages/account/dashboard.tsx index 3a167e09e2..65bc3de637 100644 --- a/sites/public/src/pages/account/dashboard.tsx +++ b/sites/public/src/pages/account/dashboard.tsx @@ -1,19 +1,15 @@ import React, { useEffect, useState, useContext } from "react" import Head from "next/head" import { NextRouter, withRouter } from "next/router" -import { - DashBlock, - DashBlocks, - HeaderBadge, - Icon, - t, - SiteAlert, - AlertBox, -} from "@bloom-housing/ui-components" +import { t, SiteAlert, AlertBox } from "@bloom-housing/ui-components" import { PageView, pushGtmEvent, AuthContext, RequireLogin } from "@bloom-housing/shared-helpers" import Layout from "../../layouts/application" import { MetaTags } from "../../components/shared/MetaTags" import { UserStatus } from "../../lib/constants" +import { Button, Card, Grid } from "@bloom-housing/ui-seeds" +import { AccountCard } from "../../components/account/AccountCard" + +import styles from "./account.module.scss" interface DashboardProps { router: NextRouter @@ -44,12 +40,6 @@ function Dashboard(props: DashboardProps) { setAlertMessage(null) } - const settingsIcon = ( - - - - ) - return ( @@ -63,28 +53,44 @@ function Dashboard(props: DashboardProps) { )}
-
+
- -
-

{t("nav.myDashboard")}

- - } - dataTestId={"account-dashboard-applications"} - > - - -
+

{t("nav.myDashboard")}

+ + + + + + + + + + + + + + + + + +
diff --git a/sites/public/src/pages/account/edit.tsx b/sites/public/src/pages/account/edit.tsx index be06bee8e8..ada40f6a88 100644 --- a/sites/public/src/pages/account/edit.tsx +++ b/sites/public/src/pages/account/edit.tsx @@ -7,8 +7,6 @@ dayjs.extend(customParseFormat) import { useForm } from "react-hook-form" import { Field, - FormCard, - Icon, Form, emailRegex, t, @@ -19,11 +17,14 @@ import { DOBField, DOBFieldValues, } from "@bloom-housing/ui-components" -import { Button } from "@bloom-housing/ui-seeds" +import { Button, Card } from "@bloom-housing/ui-seeds" import Link from "next/link" import { PageView, pushGtmEvent, AuthContext, RequireLogin } from "@bloom-housing/shared-helpers" import { UserStatus } from "../../lib/constants" import FormsLayout from "../../layouts/forms" +import { AccountCard } from "../../components/account/AccountCard" + +import styles from "./account.module.scss" type AlertMessage = { type: AlertTypes @@ -149,102 +150,111 @@ const Edit = () => { return ( - -
- -

{t("account.accountSettings")}

-
- -
+ + <> + {nameAlert && ( - setNameAlert(null)} inverted closeable> + setNameAlert(null)} + className="my-0" + inverted + closeable + > {nameAlert.message} )} -
- - - + + + + - + - -
- -
-
- -
+
+ {dobAlert && ( - setDobAlert(null)} inverted closeable> + setDobAlert(null)} + className="my-0" + inverted + closeable + > {dobAlert.message} )} -
- -
- -
-
- -
+
+ {emailAlert && ( { {emailAlert.message} )} -
- -
- -
-
- -
+
+ {passwordAlert && ( setPasswordAlert(null)} + className="my-0" inverted closeable > {passwordAlert.message} )} -
-
- - {t("authentication.createAccount.password")} - -

{t("account.settings.passwordRemember")}

-
- -
- {t("authentication.signIn.forgotPassword")} + +
+
+ + {t("authentication.createAccount.password")} + +

{t("account.settings.passwordRemember")}

+
+ + + + {t("authentication.signIn.forgotPassword")} + +
-
-
{ error={errors.password} errorMessage={t("authentication.signIn.passwordError")} register={register} - className={"mb-1"} /> -
-
value === password.current || @@ -341,19 +350,16 @@ const Edit = () => { error={errors.passwordConfirmation} errorMessage={t("authentication.createAccount.errors.passwordMismatch")} register={register} - className={"mb-1"} /> -
-
- -
-
-
- -
+ + + + +
) From ad9422adbddd6f4e096bc2a11baaa8668c2c9d6b Mon Sep 17 00:00:00 2001 From: ColinBuyck <53269332+ColinBuyck@users.noreply.github.com> Date: Mon, 29 Jan 2024 15:28:41 -0800 Subject: [PATCH 03/20] fix: add divider width (#3841) * fix: add divider width * fix: remove space --- sites/public/src/components/account/AccountCard.module.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/sites/public/src/components/account/AccountCard.module.scss b/sites/public/src/components/account/AccountCard.module.scss index 7cfd3921ac..485bfb787a 100644 --- a/sites/public/src/components/account/AccountCard.module.scss +++ b/sites/public/src/components/account/AccountCard.module.scss @@ -3,6 +3,7 @@ --card-header-padding-inline-mobile: var(--seeds-s4); --card-content-padding-inline-mobile: var(--seeds-s4); --card-border-width: 0rem; + --card-divider-width: var(--seeds-border-1); width: 100%; @media (max-width: theme("screens.sm")) { --card-spacing-lg: var(--seeds-s6); From 3c66653c17f6f2aa77b122eca85a3b0a942814a4 Mon Sep 17 00:00:00 2001 From: cade-exygy <131277283+cade-exygy@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:47:17 -0600 Subject: [PATCH 04/20] feat: 3753/ma sign in copy (#3811) * feat: add sign-in copy for mandated accounts * refactor: signUpBenefits component * feat(component): allow classNames to be applied and overridden * feat: allow Sign Copy to be mobile responsive * feat: show and hide correct layout based on screen size * refactor: signUpBenefits component * fix: 3753 fix typescript errors * fix: fix null errors * fix: remove type cast * fix: fix import * fix: 3753 remove duplicate sign in form * fix: add feature toggle * fix: clean up sign-in page * fix: address issue with email input losing focus * fix: add feature toggle * fix: remvoe MA flag from circleCI * fix: sort strings * refactor: signUpBenefitsHeadingGroup component * fix: style fixes * fix: adjust padding * refactor: clean up classNames --- .circleci/config.yml | 1 - shared-helpers/src/locales/general.json | 5 ++ .../src/components/account/SignUpBenefits.tsx | 33 ++++++++ sites/public/src/layouts/forms.tsx | 9 ++- sites/public/src/pages/sign-in.tsx | 81 +++++++++++++++---- 5 files changed, 108 insertions(+), 21 deletions(-) create mode 100644 sites/public/src/components/account/SignUpBenefits.tsx diff --git a/.circleci/config.yml b/.circleci/config.yml index b57191d555..e1e3432a9e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -30,7 +30,6 @@ executors: # DB URL for the jest tests per ormconfig.test.ts TEST_DATABASE_URL: "postgres://bloom-ci@localhost:5432/bloom" PARTNERS_PORTAL_URL: "http://localhost:3001" - jobs: setup: executor: standard-node diff --git a/shared-helpers/src/locales/general.json b/shared-helpers/src/locales/general.json index 324fc40f45..66454ac91f 100644 --- a/shared-helpers/src/locales/general.json +++ b/shared-helpers/src/locales/general.json @@ -15,6 +15,11 @@ "account.viewApplications": "View applications", "account.myApplicationsSubtitle": "See lottery dates and listings for properties for which you've applied", "account.noApplications": "It looks like you haven't applied to any listings yet.", + "account.signUpSaveTime.applyFaster": "Apply faster with saved application details", + "account.signUpSaveTime.checkStatus": "Check on the status of an application at any time", + "account.signUpSaveTime.resetPassword": "Simply reset your password if you forget it", + "account.signUpSaveTime.subTitle": "Having an account will save you time by using saved application details, and allow you to check the status of an application at anytime.", + "account.signUpSaveTime.title": "Sign up quickly and check application status at anytime", "account.settings.alerts.currentPassword": "Invalid current password. Please try again.", "account.settings.alerts.dobSuccess": "Birthdate update successful", "account.settings.alerts.emailSuccess": "Email update successful", diff --git a/sites/public/src/components/account/SignUpBenefits.tsx b/sites/public/src/components/account/SignUpBenefits.tsx new file mode 100644 index 0000000000..070292fd6e --- /dev/null +++ b/sites/public/src/components/account/SignUpBenefits.tsx @@ -0,0 +1,33 @@ +import { Icon } from "@bloom-housing/ui-seeds" +import { faStopwatch, faEye, faLock } from "@fortawesome/free-solid-svg-icons" +import { t } from "@bloom-housing/ui-components" + +type SignUpBenefitsProps = { + className?: string + idTag?: string +} +const SignUpBenefits = (props: SignUpBenefitsProps) => { + const iconListItems = [ + { icon: faStopwatch, text: t("account.signUpSaveTime.applyFaster") }, + { icon: faEye, text: t("account.signUpSaveTime.checkStatus") }, + { icon: faLock, text: t("account.signUpSaveTime.resetPassword") }, + ] + const classNames = ["flex flex-col pt-6 pb-6 pr-4 pl-4 md:p-0"] + if (props.className) classNames.push(props.className) + return ( +
    + {iconListItems.map((item) => ( +
  • + +

    {item.text}

    +
  • + ))} +
+ ) +} + +export default SignUpBenefits diff --git a/sites/public/src/layouts/forms.tsx b/sites/public/src/layouts/forms.tsx index d8967a01a5..526b1cb940 100644 --- a/sites/public/src/layouts/forms.tsx +++ b/sites/public/src/layouts/forms.tsx @@ -4,16 +4,19 @@ import { ApplicationTimeout } from "../components/applications/ApplicationTimeou interface FormLayoutProps { children?: React.ReactNode + className?: string } const FormLayout = (props: FormLayoutProps) => { + const classNames = [ + "md:mb-20 md:mt-12 mx-auto sm:max-w-lg max-w-full print:my-0 print:max-w-full", + ] + if (props.className) classNames.push(props.className) return ( <>
-
- {props.children} -
+
{props.children}
diff --git a/sites/public/src/pages/sign-in.tsx b/sites/public/src/pages/sign-in.tsx index 77d0163312..5d20447b21 100644 --- a/sites/public/src/pages/sign-in.tsx +++ b/sites/public/src/pages/sign-in.tsx @@ -15,6 +15,8 @@ import { } from "@bloom-housing/shared-helpers" import { UserStatus } from "../lib/constants" import { EnumUserErrorExtraModelUserErrorMessages } from "@bloom-housing/backend-core/types" +import { HeadingGroup } from "@bloom-housing/ui-seeds" +import SignUpBenefits from "../components/account/SignUpBenefits" const SignIn = () => { const { login, userService } = useContext(AuthContext) @@ -119,31 +121,76 @@ const SignIn = () => { useEffect(() => { if ( - networkError?.error.response.data?.message === + networkError?.error?.response?.data?.message === EnumUserErrorExtraModelUserErrorMessages.accountNotConfirmed ) { setConfirmationStatusModal(true) } }, [networkError]) + const SignUpBenefitsHeadingGroup = (props: { mobileView: boolean }) => { + const classNames = props.mobileView ? "py-6 px-4" : "" + return ( + + ) + } + return ( <> - - void onSubmit(data)} - control={{ register, errors, handleSubmit, watch }} - networkStatus={{ - content: networkStatusContent, - type: networkStatusType, - reset: () => { - reset() - resetNetworkError() - setConfirmationStatusMessage(undefined) - }, - }} - showRegisterBtn={true} - /> - + {process.env.showMandatedAccounts ? ( + +
+
+ +
+
+ void onSubmit(data)} + control={{ register, errors, handleSubmit, watch }} + networkStatus={{ + content: networkStatusContent, + type: networkStatusType, + reset: () => { + reset() + resetNetworkError() + setConfirmationStatusMessage(undefined) + }, + }} + showRegisterBtn={true} + /> +
+
+
+ + +
+
+ +
+
+ ) : ( + + void onSubmit(data)} + control={{ register, errors, handleSubmit, watch }} + networkStatus={{ + content: networkStatusContent, + type: networkStatusType, + reset: () => { + reset() + resetNetworkError() + setConfirmationStatusMessage(undefined) + }, + }} + showRegisterBtn={true} + /> + + )} Date: Thu, 8 Feb 2024 09:47:40 -0600 Subject: [PATCH 05/20] feat: 3760/redirect to application (#3839) * feat: redirect user after forget password email * refactor: parse query params as strings * feat: redirect user to application after create account * feat: confirmation Modal redirect * feat: redirect after resendConfirmation button * fix: add SHOW_MANDATED_ACCOUNTS var * refactor: check feature toggle first * fix: maintain default behavior when SHOW_MANDATED_ACCOUNTS is FALSE * refactor: remove bend feature toggle * refactor: add helper * refactor: helper function to generate email url * refactor: getListingRedirectUrl helper * style: cleanup * fix: cleanup --- .../core/src/auth/services/user.service.ts | 3 ++- backend/core/src/email/email.service.ts | 3 ++- .../src/shared/utils/get-public-email-url.ts | 18 +++++++++++++++ shared-helpers/src/auth/AuthContext.ts | 23 +++++++++++-------- .../src/utilities/getListingRedirectUrl.ts | 8 +++++++ .../src/views/sign-in/FormSignIn.tsx | 10 ++++++-- .../components/account/ConfirmationModal.tsx | 16 ++++++++++--- .../applications/start/choose-language.tsx | 7 +++--- sites/public/src/pages/create-account.tsx | 22 +++++++++++------- sites/public/src/pages/forgot-password.tsx | 5 ++-- sites/public/src/pages/reset-password.tsx | 11 ++++++++- 11 files changed, 96 insertions(+), 30 deletions(-) create mode 100644 backend/core/src/shared/utils/get-public-email-url.ts create mode 100644 shared-helpers/src/utilities/getListingRedirectUrl.ts diff --git a/backend/core/src/auth/services/user.service.ts b/backend/core/src/auth/services/user.service.ts index fb0a8b235a..21127eec37 100644 --- a/backend/core/src/auth/services/user.service.ts +++ b/backend/core/src/auth/services/user.service.ts @@ -50,6 +50,7 @@ import { Request as ExpressRequest, Response } from "express" import { UserProfileUpdateDto } from "../dto/user-profile.dto" import { Listing } from "../../listings/entities/listing.entity" import { ListingsService } from "../../listings/listings.service" +import { getPublicEmailURL } from "../../shared/utils/get-public-email-url" dayjs.extend(advancedFormat) @@ -621,7 +622,7 @@ export class UserService { } private static getPublicConfirmationUrl(appUrl: string, user: User) { - return `${appUrl}?token=${user.confirmationToken}` + return getPublicEmailURL(appUrl, user.confirmationToken) } private static getPartnersConfirmationUrl(appUrl: string, user: User) { diff --git a/backend/core/src/email/email.service.ts b/backend/core/src/email/email.service.ts index df42b3bc7d..9467f41808 100644 --- a/backend/core/src/email/email.service.ts +++ b/backend/core/src/email/email.service.ts @@ -25,6 +25,7 @@ import { Translation } from "../translations/entities/translation.entity" import { ListingEventType, Unit } from "../../types" import { formatLocalDate } from "../shared/utils/format-local-date" import { formatCommunityType } from "../listings/helpers" +import { getPublicEmailURL } from "../shared/utils/get-public-email-url" type EmailAttachmentData = { data: string @@ -244,8 +245,8 @@ export class EmailService { const jurisdiction = await this.getUserJurisdiction(user) void (await this.loadTranslations(jurisdiction, user.language)) const compiledTemplate = this.template("forgot-password") - const resetUrl = `${appUrl}/reset-password?token=${user.resetToken}` + const resetUrl = getPublicEmailURL(appUrl, user.resetToken, "/reset-password") if (this.configService.get("NODE_ENV") == "production") { Logger.log( `Preparing to send a forget password email to ${user.email} from ${jurisdiction.emailFromAddress}...` diff --git a/backend/core/src/shared/utils/get-public-email-url.ts b/backend/core/src/shared/utils/get-public-email-url.ts new file mode 100644 index 0000000000..2e6a2912a0 --- /dev/null +++ b/backend/core/src/shared/utils/get-public-email-url.ts @@ -0,0 +1,18 @@ +/** + * Creates a email URL object from passed url applies redirectUrl and listingId query params if they exist + * If they do not exist, the return value will be the email url with just the necessary token + */ + +export const getPublicEmailURL = (url: string, token: string, actionPath?: string): string => { + const urlObj = new URL(url) + + const redirectUrl = urlObj.searchParams.get("redirectUrl") + const listingId = urlObj.searchParams.get("listingId") + + let emailUrl = `${urlObj.origin}${urlObj.pathname}/${actionPath ? actionPath : ""}?token=${token}` + + if (!!redirectUrl && !!listingId) { + emailUrl = emailUrl.concat(`&redirectUrl=${redirectUrl}&listingId=${listingId}`) + } + return emailUrl +} diff --git a/shared-helpers/src/auth/AuthContext.ts b/shared-helpers/src/auth/AuthContext.ts index 9594e411c7..13afca9f9c 100644 --- a/shared-helpers/src/auth/AuthContext.ts +++ b/shared-helpers/src/auth/AuthContext.ts @@ -35,6 +35,7 @@ import qs from "qs" import axiosStatic from "axios" import { ConfigContext } from "./ConfigContext" import { createAction, createReducer } from "typesafe-actions" +import { getListingRedirectUrl } from "../utilities/getListingRedirectUrl" type ContextProps = { amiChartsService: AmiChartsService @@ -63,9 +64,9 @@ type ContextProps = { ) => Promise signOut: () => void confirmAccount: (token: string) => Promise - forgotPassword: (email: string) => Promise - createUser: (user: UserCreate) => Promise - resendConfirmation: (email: string) => Promise + forgotPassword: (email: string, listingIdRedirect?: string) => Promise + createUser: (user: UserCreate, listingIdRedirect?: string) => Promise + resendConfirmation: (email: string, listingIdRedirect?: string) => Promise initialStateLoaded: boolean loading: boolean profile?: User @@ -286,33 +287,37 @@ export const AuthProvider: FunctionComponent = ({ child dispatch(stopLoading()) } }, - createUser: async (user: UserCreate) => { + createUser: async (user: UserCreate, listingIdRedirect) => { dispatch(startLoading()) + const appUrl = getListingRedirectUrl(listingIdRedirect) try { const response = await userService?.create({ - body: { ...user, appUrl: window.location.origin }, + body: { ...user, appUrl }, }) return response } finally { dispatch(stopLoading()) } }, - resendConfirmation: async (email: string) => { + resendConfirmation: async (email: string, listingIdRedirect) => { dispatch(startLoading()) + const appUrl = getListingRedirectUrl(listingIdRedirect) try { const response = await userService?.resendConfirmation({ - body: { email, appUrl: window.location.origin }, + body: { email, appUrl }, }) return response } finally { dispatch(stopLoading()) } }, - forgotPassword: async (email) => { + forgotPassword: async (email, listingIdRedirect) => { dispatch(startLoading()) try { + const appUrl = getListingRedirectUrl(listingIdRedirect) + const response = await userService?.forgotPassword({ - body: { email, appUrl: window.location.origin }, + body: { email, appUrl }, }) return response?.message } finally { diff --git a/shared-helpers/src/utilities/getListingRedirectUrl.ts b/shared-helpers/src/utilities/getListingRedirectUrl.ts new file mode 100644 index 0000000000..5856020621 --- /dev/null +++ b/shared-helpers/src/utilities/getListingRedirectUrl.ts @@ -0,0 +1,8 @@ +export const getListingRedirectUrl = ( + listingIdRedirect: string | undefined, + path: string = window.location.origin +) => { + return process.env.showMandatedAccounts && listingIdRedirect + ? `${path}?redirectUrl=/applications/start/choose-language&listingId=${listingIdRedirect}` + : path +} diff --git a/shared-helpers/src/views/sign-in/FormSignIn.tsx b/shared-helpers/src/views/sign-in/FormSignIn.tsx index cd2c62bdb4..19c5df2d3a 100644 --- a/shared-helpers/src/views/sign-in/FormSignIn.tsx +++ b/shared-helpers/src/views/sign-in/FormSignIn.tsx @@ -4,6 +4,8 @@ import { Button } from "@bloom-housing/ui-seeds" import { FormSignInErrorBox } from "./FormSignInErrorBox" import { NetworkStatus } from "../../auth/catchNetworkError" import type { UseFormMethods } from "react-hook-form" +import { useRouter } from "next/router" +import { getListingRedirectUrl } from "../../utilities/getListingRedirectUrl" export type FormSignInProps = { control: FormSignInControl @@ -34,6 +36,10 @@ const FormSignIn = ({ window.scrollTo(0, 0) } const { LinkComponent } = useContext(NavigationContext) + const router = useRouter() + const listingIdRedirect = router.query?.listingId as string + const forgetPasswordURL = getListingRedirectUrl(listingIdRedirect, "/forgot-password") + const createAccountUrl = getListingRedirectUrl(listingIdRedirect, "/create-account") return ( @@ -60,7 +66,7 @@ const FormSignIn = ({ /> @@ -88,7 +94,7 @@ const FormSignIn = ({

{t("authentication.createAccount.noAccount")}

-
diff --git a/sites/public/src/components/account/ConfirmationModal.tsx b/sites/public/src/components/account/ConfirmationModal.tsx index bd671b6055..06bf5b1e2b 100644 --- a/sites/public/src/components/account/ConfirmationModal.tsx +++ b/sites/public/src/components/account/ConfirmationModal.tsx @@ -27,7 +27,8 @@ const ConfirmationModal = (props: ConfirmationModalProps) => { const onSubmit = async ({ email }) => { try { - await resendConfirmation(email) + const listingId = router.query?.listingId as string + await resendConfirmation(email, listingId) setSiteAlertMessage(t(`authentication.createAccount.emailSent`), "success") setOpenModal(false) @@ -39,12 +40,21 @@ const ConfirmationModal = (props: ConfirmationModalProps) => { } useEffect(() => { + const redirectUrl = router.query?.redirectUrl as string + const listingId = router.query?.listingId as string + + const routerRedirectUrl = + process.env.showMandatedAccounts && redirectUrl && listingId + ? `${redirectUrl}` + : "/account/dashboard" if (router?.query?.token && !profile) { confirmAccount(router.query.token.toString()) .then(() => { void router.push({ - pathname: "/account/dashboard", - query: { alert: `authentication.createAccount.accountConfirmed` }, + pathname: routerRedirectUrl, + query: process.env.showMandatedAccounts + ? { listingId: listingId } + : { alert: `authentication.createAccount.accountConfirmed` }, }) window.scrollTo(0, 0) }) diff --git a/sites/public/src/pages/applications/start/choose-language.tsx b/sites/public/src/pages/applications/start/choose-language.tsx index bded70d86c..31f32f008a 100644 --- a/sites/public/src/pages/applications/start/choose-language.tsx +++ b/sites/public/src/pages/applications/start/choose-language.tsx @@ -67,8 +67,9 @@ const ApplicationChooseLanguage = (props: ChooseLanguageProps) => { conductor.reset() if (!router.isReady && !listingId) return if (router.isReady && !listingId) { - void router.push("/") - return + return process.env.showMandatedAccounts && initialStateLoaded && profile + ? undefined + : void router.push("/") } if (!context.listing || context.listing.id !== listingId) { @@ -77,7 +78,7 @@ const ApplicationChooseLanguage = (props: ChooseLanguageProps) => { conductor.listing = context.listing setListing(context.listing) } - }, [router, conductor, context, listingId, props]) + }, [router, conductor, context, listingId, props, initialStateLoaded, profile]) useEffect(() => { if (listing?.status === "closed") { diff --git a/sites/public/src/pages/create-account.tsx b/sites/public/src/pages/create-account.tsx index 1b6bc88894..0bbab86a27 100644 --- a/sites/public/src/pages/create-account.tsx +++ b/sites/public/src/pages/create-account.tsx @@ -32,6 +32,7 @@ export default () => { const [openModal, setOpenModal] = useState(false) const router = useRouter() const language = router.locale + const listingId = router.query?.listingId as string const email = useRef({}) const password = useRef({}) email.current = watch("email", "") @@ -48,11 +49,16 @@ export default () => { const onSubmit = async (data) => { try { const { dob, ...rest } = data - await createUser({ - ...rest, - dob: dayjs(`${dob.birthYear}-${dob.birthMonth}-${dob.birthDay}`), - language, - }) + const listingIdRedirect = + process.env.showMandatedAccounts && listingId ? listingId : undefined + await createUser( + { + ...rest, + dob: dayjs(`${dob.birthYear}-${dob.birthMonth}-${dob.birthDay}`), + language, + }, + listingIdRedirect + ) setOpenModal(true) } catch (err) { @@ -255,14 +261,14 @@ export default () => { email: email.current, })} onClose={() => { - void router.push("/") + void router.push("/sign-in") window.scrollTo(0, 0) }} actions={[ - - - - -
-

{t("account.haveAnAccount")}

- - -
-
+ + + + {t("account.haveAnAccount")} + + + + + + Date: Fri, 9 Feb 2024 15:27:44 -0600 Subject: [PATCH 07/20] feat: create Sign Up Copy (#3880) * feat: create Sign Up Copy * fix: style fix * fix: reinstate success dto * fix: update icon margin --------- Co-authored-by: ColinBuyck Co-authored-by: cliu02 <32694266+cliu02@users.noreply.github.com> --- .../src/components/account/SignUpBenefits.tsx | 2 +- .../account/SignUpBenefitsHeadingGroup.tsx | 16 + sites/public/src/pages/create-account.tsx | 348 ++++++++++-------- sites/public/src/pages/sign-in.tsx | 91 ++--- .../styles/sign-up-benefits.module.scss | 54 +++ 5 files changed, 299 insertions(+), 212 deletions(-) create mode 100644 sites/public/src/components/account/SignUpBenefitsHeadingGroup.tsx create mode 100644 sites/public/styles/sign-up-benefits.module.scss diff --git a/sites/public/src/components/account/SignUpBenefits.tsx b/sites/public/src/components/account/SignUpBenefits.tsx index 070292fd6e..7b18d551fb 100644 --- a/sites/public/src/components/account/SignUpBenefits.tsx +++ b/sites/public/src/components/account/SignUpBenefits.tsx @@ -17,7 +17,7 @@ const SignUpBenefits = (props: SignUpBenefitsProps) => { return (
    {iconListItems.map((item) => ( -
  • +
  • { + const classNames = props.mobileView ? "py-6 px-4" : "" + return ( + + ) +} + +export default SignUpBenefitsHeadingGroup diff --git a/sites/public/src/pages/create-account.tsx b/sites/public/src/pages/create-account.tsx index 0a41e46763..9f8ca3df51 100644 --- a/sites/public/src/pages/create-account.tsx +++ b/sites/public/src/pages/create-account.tsx @@ -23,10 +23,14 @@ import FormsLayout from "../layouts/forms" import { AccountCard } from "../components/account/AccountCard" import accountCardStyles from "./account/account.module.scss" import styles from "../../styles/create-account.module.scss" +import signUpBenefitsStyles from "../../styles/sign-up-benefits.module.scss" +import SignUpBenefits from "../components/account/SignUpBenefits" +import SignUpBenefitsHeadingGroup from "../components/account/SignUpBenefitsHeadingGroup" export default () => { const { createUser, resendConfirmation } = useContext(AuthContext) const [confirmationResent, setConfirmationResent] = useState(false) + const signUpCopy = process.env.showMandatedAccounts /* Form Handler */ // eslint-disable-next-line @typescript-eslint/unbound-method const { register, handleSubmit, errors, watch } = useForm() @@ -79,165 +83,199 @@ export default () => { } return ( - - - <> - {requestError && ( - setRequestError(undefined)} type="alert"> - {requestError} - - )} - -
    - - + +
    + {signUpCopy && ( +
    + +
    + )} +
    + + <> + {requestError && ( + setRequestError(undefined)} type="alert"> + {requestError} + + )} + + + + - - + + - - + + - - - - - -

    {t("application.name.dobHelper")}

    -
    + + + + + +

    {t("application.name.dobHelper")}

    +
    - - - - - - - - value === password.current || - t("authentication.createAccount.errors.passwordMismatch"), - }} - onPaste={(e) => { - e.preventDefault() - e.nativeEvent.stopImmediatePropagation() - return false - }} - onDrop={(e) => { - e.preventDefault() - e.nativeEvent.stopImmediatePropagation() - return false - }} - error={errors.passwordConfirmation} - errorMessage={t("authentication.createAccount.errors.passwordMismatch")} - register={register} - controlClassName={styles["create-account-input"]} - label={t("authentication.createAccount.reEnterPassword")} - readerOnly - /> - - - - - {t("account.haveAnAccount")} - - - - - -
    + + + + + + + + value === password.current || + t("authentication.createAccount.errors.passwordMismatch"), + }} + onPaste={(e) => { + e.preventDefault() + e.nativeEvent.stopImmediatePropagation() + return false + }} + onDrop={(e) => { + e.preventDefault() + e.nativeEvent.stopImmediatePropagation() + return false + }} + error={errors.passwordConfirmation} + errorMessage={t("authentication.createAccount.errors.passwordMismatch")} + register={register} + controlClassName={styles["create-account-input"]} + label={t("authentication.createAccount.reEnterPassword")} + readerOnly + /> + + + + + {t("account.haveAnAccount")} + + + + + + +
    + {signUpCopy && ( +
    +
    + + +
    +
    + )} + {signUpCopy && ( +
    + +
    + )} +
    { const { login, userService } = useContext(AuthContext) + const signUpCopy = process.env.showMandatedAccounts /* Form Handler */ // This is causing a linting issue with unbound-method, see open issue as of 10/21/2020: // https://github.com/react-hook-form/react-hook-form/issues/2887 @@ -128,69 +130,46 @@ const SignIn = () => { } }, [networkError]) - const SignUpBenefitsHeadingGroup = (props: { mobileView: boolean }) => { - const classNames = props.mobileView ? "py-6 px-4" : "" - return ( - - ) - } - return ( <> - {process.env.showMandatedAccounts ? ( - -
    -
    + +
    + {signUpCopy && ( +
    -
    - void onSubmit(data)} - control={{ register, errors, handleSubmit, watch }} - networkStatus={{ - content: networkStatusContent, - type: networkStatusType, - reset: () => { - reset() - resetNetworkError() - setConfirmationStatusMessage(undefined) - }, - }} - showRegisterBtn={true} - /> -
    -
    -
    + )} +
    + void onSubmit(data)} + control={{ register, errors, handleSubmit, watch }} + networkStatus={{ + content: networkStatusContent, + type: networkStatusType, + reset: () => { + reset() + resetNetworkError() + setConfirmationStatusMessage(undefined) + }, + }} + showRegisterBtn={true} + /> +
    + {signUpCopy && ( +
    +
    - -
    - - ) : ( - - void onSubmit(data)} - control={{ register, errors, handleSubmit, watch }} - networkStatus={{ - content: networkStatusContent, - type: networkStatusType, - reset: () => { - reset() - resetNetworkError() - setConfirmationStatusMessage(undefined) - }, - }} - showRegisterBtn={true} - /> - - )} + )} + {signUpCopy && ( +
    + +
    + )} +
    + Date: Mon, 12 Feb 2024 08:12:11 -0800 Subject: [PATCH 08/20] feat: add MA sign in styling (#3820) --- .../views/accounts}/AccountCard.module.scss | 0 .../src/views/accounts}/AccountCard.tsx | 2 +- .../src/views/accounts}/CustomIconMap.tsx | 0 .../src/views/accounts}/CustomIcons.tsx | 1 + .../src/views/sign-in/FormSignIn.tsx | 121 +++++++++--------- .../src/views/sign-in/FormSignInErrorBox.tsx | 12 +- .../public/src/pages/account/applications.tsx | 2 +- sites/public/src/pages/account/dashboard.tsx | 2 +- sites/public/src/pages/account/edit.tsx | 2 +- sites/public/src/pages/create-account.tsx | 2 +- sites/public/styles/sign-in.module.scss | 6 + 11 files changed, 85 insertions(+), 65 deletions(-) rename {sites/public/src/components/account => shared-helpers/src/views/accounts}/AccountCard.module.scss (100%) rename {sites/public/src/components/account => shared-helpers/src/views/accounts}/AccountCard.tsx (95%) rename {sites/public/src/components/shared => shared-helpers/src/views/accounts}/CustomIconMap.tsx (100%) rename {sites/public/src/components/shared => shared-helpers/src/views/accounts}/CustomIcons.tsx (99%) create mode 100644 sites/public/styles/sign-in.module.scss diff --git a/sites/public/src/components/account/AccountCard.module.scss b/shared-helpers/src/views/accounts/AccountCard.module.scss similarity index 100% rename from sites/public/src/components/account/AccountCard.module.scss rename to shared-helpers/src/views/accounts/AccountCard.module.scss diff --git a/sites/public/src/components/account/AccountCard.tsx b/shared-helpers/src/views/accounts/AccountCard.tsx similarity index 95% rename from sites/public/src/components/account/AccountCard.tsx rename to shared-helpers/src/views/accounts/AccountCard.tsx index 588ac4f002..f199d7809c 100644 --- a/sites/public/src/components/account/AccountCard.tsx +++ b/shared-helpers/src/views/accounts/AccountCard.tsx @@ -2,7 +2,7 @@ import { Heading, HeadingGroup, Icon } from "@bloom-housing/ui-seeds" import Card from "@bloom-housing/ui-seeds/src/blocks/Card" import React from "react" import styles from "./AccountCard.module.scss" -import { CustomIconMap, CustomIconType } from "../shared/CustomIconMap" +import { CustomIconMap, CustomIconType } from "./CustomIconMap" interface AccountCardProps { iconSymbol: CustomIconType diff --git a/sites/public/src/components/shared/CustomIconMap.tsx b/shared-helpers/src/views/accounts/CustomIconMap.tsx similarity index 100% rename from sites/public/src/components/shared/CustomIconMap.tsx rename to shared-helpers/src/views/accounts/CustomIconMap.tsx diff --git a/sites/public/src/components/shared/CustomIcons.tsx b/shared-helpers/src/views/accounts/CustomIcons.tsx similarity index 99% rename from sites/public/src/components/shared/CustomIcons.tsx rename to shared-helpers/src/views/accounts/CustomIcons.tsx index 7d4172a4a7..eaa5460cb4 100644 --- a/sites/public/src/components/shared/CustomIcons.tsx +++ b/shared-helpers/src/views/accounts/CustomIcons.tsx @@ -1,4 +1,5 @@ import { t } from "@bloom-housing/ui-components" +import React from "react" export const Application = ( -
    - -

    {t(`nav.signIn`)}

    -
    - -
    -
    - + + <> + + + + + + +
    + +
    + +
    + {showRegisterBtn && ( + + + {t("authentication.createAccount.noAccount")} + - - - - -
    - -
    - -
    - {showRegisterBtn && ( -
    -

    {t("authentication.createAccount.noAccount")}

    - - -
    - )} - + + )} + + ) } diff --git a/shared-helpers/src/views/sign-in/FormSignInErrorBox.tsx b/shared-helpers/src/views/sign-in/FormSignInErrorBox.tsx index 39fd476021..f3b4874170 100644 --- a/shared-helpers/src/views/sign-in/FormSignInErrorBox.tsx +++ b/shared-helpers/src/views/sign-in/FormSignInErrorBox.tsx @@ -7,6 +7,7 @@ export type FormSignInErrorBoxProps = { errors: FormSignInErrorBoxControl["errors"] networkStatus: NetworkStatus errorMessageId: string + className?: string } export type FormSignInErrorBoxControl = { @@ -14,9 +15,16 @@ export type FormSignInErrorBoxControl = { control: UseFormMethods["control"] } -const FormSignInErrorBox = ({ networkStatus, errors, errorMessageId }: FormSignInErrorBoxProps) => { +const FormSignInErrorBox = ({ + networkStatus, + errors, + errorMessageId, + className, +}: FormSignInErrorBoxProps) => { + const classNames = ["border-b"] + if (className) classNames.push(className) return ( -
    +
    {Object.entries(errors).length > 0 && !networkStatus.content && ( {errors.authentication ? errors.authentication.message : t("errors.errorsToResolve")} diff --git a/sites/public/src/pages/account/applications.tsx b/sites/public/src/pages/account/applications.tsx index 8d4fd365c1..9a1781dd30 100644 --- a/sites/public/src/pages/account/applications.tsx +++ b/sites/public/src/pages/account/applications.tsx @@ -7,7 +7,7 @@ import Layout from "../../layouts/application" import { StatusItemWrapper, AppWithListing } from "./StatusItemWrapper" import { MetaTags } from "../../components/shared/MetaTags" import { UserStatus } from "../../lib/constants" -import { AccountCard } from "../../components/account/AccountCard" +import { AccountCard } from "@bloom-housing/shared-helpers/src/views/accounts/AccountCard" import styles from "../../pages/account/account.module.scss" diff --git a/sites/public/src/pages/account/dashboard.tsx b/sites/public/src/pages/account/dashboard.tsx index 65bc3de637..df964db8d5 100644 --- a/sites/public/src/pages/account/dashboard.tsx +++ b/sites/public/src/pages/account/dashboard.tsx @@ -7,7 +7,7 @@ import Layout from "../../layouts/application" import { MetaTags } from "../../components/shared/MetaTags" import { UserStatus } from "../../lib/constants" import { Button, Card, Grid } from "@bloom-housing/ui-seeds" -import { AccountCard } from "../../components/account/AccountCard" +import { AccountCard } from "@bloom-housing/shared-helpers/src/views/accounts/AccountCard" import styles from "./account.module.scss" diff --git a/sites/public/src/pages/account/edit.tsx b/sites/public/src/pages/account/edit.tsx index ada40f6a88..74d39abdc8 100644 --- a/sites/public/src/pages/account/edit.tsx +++ b/sites/public/src/pages/account/edit.tsx @@ -22,7 +22,7 @@ import Link from "next/link" import { PageView, pushGtmEvent, AuthContext, RequireLogin } from "@bloom-housing/shared-helpers" import { UserStatus } from "../../lib/constants" import FormsLayout from "../../layouts/forms" -import { AccountCard } from "../../components/account/AccountCard" +import { AccountCard } from "@bloom-housing/shared-helpers/src/views/accounts/AccountCard" import styles from "./account.module.scss" diff --git a/sites/public/src/pages/create-account.tsx b/sites/public/src/pages/create-account.tsx index 9f8ca3df51..6d21f24192 100644 --- a/sites/public/src/pages/create-account.tsx +++ b/sites/public/src/pages/create-account.tsx @@ -20,7 +20,7 @@ import { useRouter } from "next/router" import { PageView, pushGtmEvent, AuthContext } from "@bloom-housing/shared-helpers" import { UserStatus } from "../lib/constants" import FormsLayout from "../layouts/forms" -import { AccountCard } from "../components/account/AccountCard" +import { AccountCard } from "@bloom-housing/shared-helpers/src/views/accounts/AccountCard" import accountCardStyles from "./account/account.module.scss" import styles from "../../styles/create-account.module.scss" import signUpBenefitsStyles from "../../styles/sign-up-benefits.module.scss" diff --git a/sites/public/styles/sign-in.module.scss b/sites/public/styles/sign-in.module.scss new file mode 100644 index 0000000000..b97924f850 --- /dev/null +++ b/sites/public/styles/sign-in.module.scss @@ -0,0 +1,6 @@ +.forgot-password { + float: right; + font-size: var(--seeds-font-size-sm); + text-decoration-line: underline; + color: var(--seeds-color-blue-900); +} \ No newline at end of file From d734a39c25c793a3e89932d8c69104d6bbe5e623 Mon Sep 17 00:00:00 2001 From: cliu02 <32694266+cliu02@users.noreply.github.com> Date: Mon, 12 Feb 2024 08:14:04 -0800 Subject: [PATCH 09/20] feat: add MA application check for signed-in user (#3850) --- shared-helpers/src/auth/UseRequireLoggedInUser.ts | 4 ++-- sites/public/src/lib/hooks.ts | 2 ++ .../src/pages/applications/start/choose-language.tsx | 9 ++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/shared-helpers/src/auth/UseRequireLoggedInUser.ts b/shared-helpers/src/auth/UseRequireLoggedInUser.ts index 835e959813..2bde9d1628 100644 --- a/shared-helpers/src/auth/UseRequireLoggedInUser.ts +++ b/shared-helpers/src/auth/UseRequireLoggedInUser.ts @@ -6,11 +6,11 @@ import { NavigationContext } from "@bloom-housing/ui-components" * Require a logged in user. Waits on initial load, then initiates a redirect to `redirectPath` if user is not * logged in. */ -function useRequireLoggedInUser(redirectPath: string) { +function useRequireLoggedInUser(redirectPath: string, disable?: boolean) { const { profile, initialStateLoaded } = useContext(AuthContext) const { router } = useContext(NavigationContext) - if (initialStateLoaded && !profile) { + if (!disable && initialStateLoaded && !profile) { void router.push(redirectPath) } return profile diff --git a/sites/public/src/lib/hooks.ts b/sites/public/src/lib/hooks.ts index 51d7783abb..4af5358c16 100644 --- a/sites/public/src/lib/hooks.ts +++ b/sites/public/src/lib/hooks.ts @@ -15,6 +15,7 @@ import { import { ParsedUrlQuery } from "querystring" import { AppSubmissionContext } from "./applications/AppSubmissionContext" import { getListingApplicationStatus } from "./helpers" +import { useRequireLoggedInUser } from "@bloom-housing/shared-helpers" export const useRedirectToPrevPage = (defaultPath = "/") => { const router = useRouter() @@ -32,6 +33,7 @@ export const useRedirectToPrevPage = (defaultPath = "/") => { } export const useFormConductor = (stepName: string) => { + useRequireLoggedInUser("/", !process.env.showMandatedAccounts) const context = useContext(AppSubmissionContext) const conductor = context.conductor diff --git a/sites/public/src/pages/applications/start/choose-language.tsx b/sites/public/src/pages/applications/start/choose-language.tsx index 31f32f008a..8eaaecf382 100644 --- a/sites/public/src/pages/applications/start/choose-language.tsx +++ b/sites/public/src/pages/applications/start/choose-language.tsx @@ -66,12 +66,11 @@ const ApplicationChooseLanguage = (props: ChooseLanguageProps) => { useEffect(() => { conductor.reset() if (!router.isReady && !listingId) return - if (router.isReady && !listingId) { - return process.env.showMandatedAccounts && initialStateLoaded && profile - ? undefined - : void router.push("/") + if (router.isReady) { + if (!listingId || (process.env.showMandatedAccounts && initialStateLoaded && !profile)) { + void router.push("/") + } } - if (!context.listing || context.listing.id !== listingId) { void loadListing(props.backendApiBase, listingId, setListing, conductor, context, "en") } else { From dc6fb3031c62eae7374599dcdf4af3e7e43e21a6 Mon Sep 17 00:00:00 2001 From: cade-exygy <131277283+cade-exygy@users.noreply.github.com> Date: Thu, 14 Dec 2023 13:05:46 -0600 Subject: [PATCH 10/20] feat: ma-3752 add flag (#3773) * feat: mA-3752 feat: add SHOW_MANDATED_ACCOUNTS flag * fix: add feature flag to bloom public next config * fix: remove flag from partners --- sites/public/.env.template | 8 +++++--- sites/public/next.config.js | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sites/public/.env.template b/sites/public/.env.template index bf0724b5c0..bdb217c3cb 100644 --- a/sites/public/.env.template +++ b/sites/public/.env.template @@ -19,10 +19,12 @@ SENTRY_ORG= # this GTM key is for local development only GTM_KEY=GTM-KF22FJP +# feature toggles +SHOW_MANDATED_ACCOUNTS=FALSE +SHOW_PROFESSIONAL_PARTNERS=TRUE + ### Begin Doorway-specific variables ### # Note: This must be kept in sync with the same env variable in backend/core # Note: BLOOM_API_BASE must match EXTERNAL_API_BASE in tasks/import-listings BLOOM_API_BASE=https://hba-dev-proxy.herokuapp.com -GOOGLE_MAPS_API_KEY=SUPER_SECRET_KEY - -SHOW_PROFESSIONAL_PARTNERS=TRUE +GOOGLE_MAPS_API_KEY=SUPER_SECRET_KEY \ No newline at end of file diff --git a/sites/public/next.config.js b/sites/public/next.config.js index 834f307228..766c931983 100644 --- a/sites/public/next.config.js +++ b/sites/public/next.config.js @@ -42,8 +42,8 @@ module.exports = withBundleAnalyzer({ cacheRevalidate: process.env.CACHE_REVALIDATE ? Number(process.env.CACHE_REVALIDATE) : 60, cloudinaryCloudName: process.env.CLOUDINARY_CLOUD_NAME, showProfessionalPartners: process.env.SHOW_PROFESSIONAL_PARTNERS === "TRUE", + showMandatedAccounts: process.env.SHOW_MANDATED_ACCOUNTS === "TRUE", notificationsSignUpUrl: process.env.NOTIFICATIONS_SIGN_UP_URL || null, - // start Doorway env variables //googleMapsApiKey: process.env.GOOGLE_MAPS_API_KEY, // moved to runtime config awsS3BucketName: process.env.AWS_S3_BUCKET_NAME, From 2b8ecdcd77fd3b25dfe2ef1b6bb4e9046ca98055 Mon Sep 17 00:00:00 2001 From: ColinBuyck <53269332+ColinBuyck@users.noreply.github.com> Date: Tue, 13 Feb 2024 11:26:36 -0800 Subject: [PATCH 11/20] fix: shared-helpers tailwind config (#479) --- sites/public/tailwind.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/sites/public/tailwind.config.js b/sites/public/tailwind.config.js index f4ca86305b..51aa076671 100644 --- a/sites/public/tailwind.config.js +++ b/sites/public/tailwind.config.js @@ -15,6 +15,7 @@ module.exports = { content: [ "./pages/**/*.tsx", "./src/**/*.tsx", + "../../node_modules/@bloom-housing/shared-helpers/src/views/**/*.tsx", "../../node_modules/@bloom-housing/ui-components/src/**/*.tsx", ], safelist: [/grid-cols-/], From 31b2780825465cfa65c3c43cb295131decee22e6 Mon Sep 17 00:00:00 2001 From: ColinBuyck Date: Tue, 13 Feb 2024 14:48:16 -0800 Subject: [PATCH 12/20] feat: account design updates (#3853) * fix: updates per Jesse feedback * fix: generalize application view * fix: heading level and typography updates * fix: confirmation page changes * fix: applications spacing changes * fix: no results updates * fix: update prisma typing * fix: back href * fix: final tweaks * fix: aligning mobile view and css class names * fix: remove testing line --- .../views/accounts/AccountCard.module.scss | 23 ++-- .../src/views/accounts/AccountCard.tsx | 4 + .../components/account/StatusItem.module.scss | 25 +++-- .../src/components/account/StatusItem.tsx | 8 +- .../SubmittedApplicationView.modules.scss | 0 .../applications/SubmittedApplicationView.tsx | 93 ++++++++++++++++ .../components/shared/FormSummaryDetails.tsx | 12 +-- .../src/pages/account/StatusItemWrapper.tsx | 6 +- .../src/pages/account/account.module.scss | 28 +++-- .../src/pages/account/application/[id].tsx | 101 ++++++------------ .../public/src/pages/account/applications.tsx | 32 +++--- sites/public/src/pages/account/dashboard.tsx | 9 +- sites/public/src/pages/account/edit.tsx | 18 ++-- sites/public/src/pages/applications/view.tsx | 81 ++------------ sites/public/src/pages/create-account.tsx | 11 +- 15 files changed, 244 insertions(+), 207 deletions(-) create mode 100644 sites/public/src/components/applications/SubmittedApplicationView.modules.scss create mode 100644 sites/public/src/components/applications/SubmittedApplicationView.tsx diff --git a/shared-helpers/src/views/accounts/AccountCard.module.scss b/shared-helpers/src/views/accounts/AccountCard.module.scss index 485bfb787a..c9fa125e30 100644 --- a/shared-helpers/src/views/accounts/AccountCard.module.scss +++ b/shared-helpers/src/views/accounts/AccountCard.module.scss @@ -1,13 +1,19 @@ .account-card { - --card-header-padding-inline-desktop: var(--seeds-s12); - --card-header-padding-inline-mobile: var(--seeds-s4); - --card-content-padding-inline-mobile: var(--seeds-s4); - --card-border-width: 0rem; - --card-divider-width: var(--seeds-border-1); width: 100%; + height: 100%; + justify-content: space-between; @media (max-width: theme("screens.sm")) { --card-spacing-lg: var(--seeds-s6); - --card-border-radius: 0rem; + } +} + +.account-card-inline-desktop { + --card-header-padding-inline-desktop: var(--seeds-s12); +} + +.account-card-inline-mobile { + @media (max-width: theme("screens.sm")) { + --card-header-padding-inline-mobile: var(--seeds-s4); } } @@ -16,8 +22,11 @@ } .account-card-heading-group { - --subheading-margin: var(--seeds-s3); --heading-margin: var(--seeds-s3); + --subheading-color: var(--seeds-text-color-light); + @media (max-width: theme("screens.sm")) { + --subheading-margin: var(--seeds-s3); + } } .account-card-heading { diff --git a/shared-helpers/src/views/accounts/AccountCard.tsx b/shared-helpers/src/views/accounts/AccountCard.tsx index f199d7809c..47ef391218 100644 --- a/shared-helpers/src/views/accounts/AccountCard.tsx +++ b/shared-helpers/src/views/accounts/AccountCard.tsx @@ -13,11 +13,15 @@ interface AccountCardProps { divider?: "flush" | "inset" headingPriority?: 1 | 2 | 3 | 4 | 5 | 6 className?: string + thinDesktop?: boolean + thinMobile?: boolean } const AccountCard = (props: AccountCardProps) => { const classNames = [styles["account-card"]] if (props.className) classNames.push(props.className) + if (!props.thinDesktop) classNames.push(styles["account-card-inline-desktop"]) + if (props.thinMobile) classNames.push(styles["account-card-inline-mobile"]) const customIcon = CustomIconMap[props.iconSymbol] diff --git a/sites/public/src/components/account/StatusItem.module.scss b/sites/public/src/components/account/StatusItem.module.scss index 8abc78ad41..203fab5a0d 100644 --- a/sites/public/src/components/account/StatusItem.module.scss +++ b/sites/public/src/components/account/StatusItem.module.scss @@ -1,8 +1,8 @@ .status-item { position: relative; padding: var(--seeds-s4); - background-color: var(--seeds-color-primary-lighter); - color: var(--seeds-gray-800); + background-color: var(--seeds-bg-color-muted); + color: var(--seeds-color-gray-900); border-bottom-width: 0.0625rem; border-style: solid; border-color: var(--seeds-color-gray-450); @@ -16,7 +16,7 @@ border-style: solid; border-color: var(--seeds-color-gray-450); margin-bottom: var(seeds-s4); - @media (max-width: theme("screens.md")) { + @media (max-width: theme("screens.sm")) { padding-bottom: var(--seeds-s2); display: block; } @@ -31,17 +31,22 @@ text-align: right; align-self: center; font-size: var(--seeds-font-size-sm); - @media (max-width: theme("screens.md")) { + color: var(--seeds-color-gray-750); + @media (max-width: theme("screens.sm")) { text-align: left; padding-top: var(--seeds-s2_5); } } +.status-item__due-date { + font-weight: var(--seeds-font-weight-semibold); +} + .status-item__content { display: flex; justify-content: space-between; padding-top: var(--seeds-s4); - @media (max-width: theme("screens.md")) { + @media (max-width: theme("screens.sm")) { display: grid; } } @@ -54,10 +59,9 @@ padding-top: 0; text-align: right; - @media (max-width: theme("screens.md")) { + @media (max-width: theme("screens.sm")) { text-align: center; padding-top: var(seeds-s4); - margin-bottom: var(--seeds-s4); } } @@ -68,15 +72,17 @@ justify-content: flex-start; padding-top: var(--seeds-s4); width: fit-content; - @media (max-width: theme("screens.md")) { + @media (max-width: theme("screens.sm")) { flex-direction: column; + padding-top: var(--seeds-s6); } } .status-item__status { padding-block: 0; font-size: var(--seeds-font-size-sm); - @media (max-width: theme("screens.md")) { + color: var(--seeds-color-gray-750); + @media (max-width: theme("screens.sm")) { padding-block: var(--seeds-s4); } } @@ -88,5 +94,6 @@ .status-item__confirm-number { font-size: var(--seeds-font-size-lg); + font-weight: var(--seeds-font-weight-semibold); padding-top: var(--seeds-s2); } diff --git a/sites/public/src/components/account/StatusItem.tsx b/sites/public/src/components/account/StatusItem.tsx index 94f32ad023..3237ee12cf 100644 --- a/sites/public/src/components/account/StatusItem.tsx +++ b/sites/public/src/components/account/StatusItem.tsx @@ -24,9 +24,7 @@ interface StatusItemProps { const StatusItem = (props: StatusItemProps) => { return ( - +

    {props.listingName}

    @@ -57,7 +55,7 @@ const StatusItem = (props: StatusItemProps) => { {props.applicationDueDate && (

    {props.strings?.applicationsDeadline ?? t("listings.applicationDeadline")}:{" "} - {props.applicationDueDate} + {props.applicationDueDate}

    )}
    @@ -70,7 +68,7 @@ const StatusItem = (props: StatusItemProps) => {
    -
    diff --git a/sites/public/src/components/applications/SubmittedApplicationView.modules.scss b/sites/public/src/components/applications/SubmittedApplicationView.modules.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/sites/public/src/components/applications/SubmittedApplicationView.tsx b/sites/public/src/components/applications/SubmittedApplicationView.tsx new file mode 100644 index 0000000000..f90ce5b75f --- /dev/null +++ b/sites/public/src/components/applications/SubmittedApplicationView.tsx @@ -0,0 +1,93 @@ +import { t } from "@bloom-housing/ui-components" +import { Button, Card, Heading, Icon } from "@bloom-housing/ui-seeds" +import FormSummaryDetails from "../shared/FormSummaryDetails" +import { listingSectionQuestions } from "@bloom-housing/shared-helpers" +import { useMemo } from "react" +import { DATE_FORMAT } from "../../lib/constants" +import dayjs from "dayjs" +import { faChevronLeft } from "@fortawesome/free-solid-svg-icons" +import { ApplicationSection, Listing } from "@bloom-housing/backend-core/types" + +interface SubmittedApplicationViewProps { + application: any + listing: Listing + backHref: string +} + +const SubmittedApplicationView = ({ + application, + listing, + backHref, +}: SubmittedApplicationViewProps) => { + const confirmationDate = useMemo(() => { + return dayjs().format(DATE_FORMAT) + }, []) + + return ( + <> + + + + {listing?.name} + + + +
    + {listing && ( + + )} +
    +
    +
    + + + + + {t("application.confirmation.informationSubmittedTitle")} + +

    + {t("application.confirmation.submitted")} + {confirmationDate} +

    +
    + +

    {`${t("application.yourLotteryNumber")}:`}

    +

    + {application?.confirmationCode || application?.id} +

    +
    + + +
    + +
    +
    +
    + + ) +} + +export { SubmittedApplicationView as default, SubmittedApplicationView } diff --git a/sites/public/src/components/shared/FormSummaryDetails.tsx b/sites/public/src/components/shared/FormSummaryDetails.tsx index 3c98a206b5..a9a6f65898 100644 --- a/sites/public/src/components/shared/FormSummaryDetails.tsx +++ b/sites/public/src/components/shared/FormSummaryDetails.tsx @@ -116,7 +116,7 @@ const FormSummaryDetails = ({ ) => { return ( <> -

    +

    {header} {editMode && !validationError && }

    @@ -161,7 +161,7 @@ const FormSummaryDetails = ({ return ( <> -

    +

    {t("t.you")} {editMode && }

    @@ -278,7 +278,7 @@ const FormSummaryDetails = ({ {application.alternateContact.type !== "" && application.alternateContact.type !== "noContact" && (
    -

    +

    {t("application.alternateContact.type.label")} {editMode && !validationError && ( @@ -339,7 +339,7 @@ const FormSummaryDetails = ({ {application.householdSize > 1 && (
    -

    +

    {t("application.household.householdMembers")} {editMode && !validationError && ( @@ -391,7 +391,7 @@ const FormSummaryDetails = ({ )}
    -

    +

    {t("application.review.householdDetails")} {editMode && !validationError && ( @@ -452,7 +452,7 @@ const FormSummaryDetails = ({ : null )} -

    +

    {t("t.income")} {editMode && !validationError && }

    diff --git a/sites/public/src/pages/account/StatusItemWrapper.tsx b/sites/public/src/pages/account/StatusItemWrapper.tsx index 90bac6ec96..4844fc8a5e 100644 --- a/sites/public/src/pages/account/StatusItemWrapper.tsx +++ b/sites/public/src/pages/account/StatusItemWrapper.tsx @@ -11,11 +11,11 @@ interface StatusItemWrapperProps { } const StatusItemWrapper = (props: StatusItemWrapperProps) => { + const applicationDueDate = props.application?.fullListing?.applicationDueDate + return ( { const router = useRouter() const applicationId = router.query.id as string - const { applicationsService, listingsService } = useContext(AuthContext) - const { profile } = useContext(AuthContext) + const { applicationsService, listingsService, profile } = useContext(AuthContext) const [application, setApplication] = useState() const [listing, setListing] = useState() const [unauthorized, setUnauthorized] = useState(false) @@ -49,71 +48,41 @@ export default () => { {noApplication && ( - {t("account.application.error")}}> -

    {t("account.application.noApplicationError")}

    - - {t("account.application.return")} - -
    + + + + {t("account.application.error")} + + + +

    {t("account.application.noApplicationError")}

    + +
    +
    )} {unauthorized && ( - {t("account.application.error")}}> -

    {t("account.application.noAccessError")}

    - - {t("account.application.return")} - -
    + + + + {t("account.application.error")} + + + +

    {t("account.application.noAccessError")}

    + +
    +
    )} {application && ( - <> - {t("account.application.confirmation")}} - > -
    - {listing && ( - - - {t("application.confirmation.viewOriginalListing")} - - - )} -
    -
    - - -
    -

    - {t("application.confirmation.informationSubmittedTitle")} -

    -

    - {t("application.confirmation.submitted")} - {dateToString(application.submissionDate)} -

    -
    -
    -

    - {t("application.confirmation.lotteryNumber")} -

    - -

    - {application.confirmationCode || application.id} -

    -
    - - - -
    -
    - -
    -
    -
    - + )}
    diff --git a/sites/public/src/pages/account/applications.tsx b/sites/public/src/pages/account/applications.tsx index 9a1781dd30..4ab8985cf1 100644 --- a/sites/public/src/pages/account/applications.tsx +++ b/sites/public/src/pages/account/applications.tsx @@ -61,21 +61,21 @@ const Applications = () => { const noApplicationsSection = () => { return ( - - {error ? ( - {`${t("account.errorFetchingApplications")}`} - ) : ( - <> - - {t("account.noApplications")} - - - - )} + +
    + {error ? ( + {`${t("account.errorFetchingApplications")}`} + ) : ( + <> + + {t("account.noApplications")} + + + + )} +
    ) } @@ -92,7 +92,9 @@ const Applications = () => { iconSymbol="application" title={t("account.myApplications")} subtitle={t("account.myApplicationsSubtitle")} + headingPriority={1} divider="inset" + thinMobile > <> diff --git a/sites/public/src/pages/account/dashboard.tsx b/sites/public/src/pages/account/dashboard.tsx index df964db8d5..e9087870e0 100644 --- a/sites/public/src/pages/account/dashboard.tsx +++ b/sites/public/src/pages/account/dashboard.tsx @@ -63,9 +63,11 @@ function Dashboard(props: DashboardProps) { iconSymbol="application" title={t("account.myApplications")} subtitle={t("account.myApplicationsSubtitle")} + thinDesktop > - + diff --git a/sites/public/src/pages/account/edit.tsx b/sites/public/src/pages/account/edit.tsx index 74d39abdc8..6334d7c9de 100644 --- a/sites/public/src/pages/account/edit.tsx +++ b/sites/public/src/pages/account/edit.tsx @@ -156,6 +156,7 @@ const Edit = () => { subtitle={t("account.accountSettingsSubtitle")} divider="inset" headingPriority={1} + thinMobile > <> @@ -170,7 +171,7 @@ const Edit = () => { {nameAlert.message} )} - +