Skip to content

Commit

Permalink
release: various Toast updates (#818)
Browse files Browse the repository at this point in the history
* fix: restore toasts in a way which prevents infinite rerenders (bloom-housing#4302)

* fix: restore toasts in a way which prevents infinite rerenders

* fix: linting

* fix: use a ref to hold a stable reference for addToast in effects

* chore: add comment

---------

Co-authored-by: Emily Jablonski <[email protected]>
(cherry picked from commit 4445b97)

* feat: update toast messages for Forgot Password (bloom-housing#4466)

(cherry picked from commit 2edb70f)
  • Loading branch information
jaredcwhite authored Nov 26, 2024
1 parent ad854de commit 061c810
Show file tree
Hide file tree
Showing 10 changed files with 45 additions and 22 deletions.
8 changes: 5 additions & 3 deletions shared-helpers/src/auth/RequireLogin.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { FunctionComponent, useContext, useEffect, useState } from "react"
import { NavigationContext } from "@bloom-housing/ui-components"
import { AuthContext } from "./AuthContext"
import { MessageContext } from "../utilities/MessageContext"
import { useToastyRef } from "../utilities/MessageContext"

// See https://github.com/Microsoft/TypeScript/issues/14094
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never }
Expand Down Expand Up @@ -31,7 +31,7 @@ const RequireLogin: FunctionComponent<RequireLoginProps> = ({
}) => {
const { router } = useContext(NavigationContext)
const { profile, initialStateLoaded } = useContext(AuthContext)
const { addToast } = useContext(MessageContext)
const toastyRef = useToastyRef()
const [hasTerms, setHasTerms] = useState(false)

// Parse just the pathname portion of the signInPath (in case we want to pass URL params)
Expand All @@ -56,6 +56,8 @@ const RequireLogin: FunctionComponent<RequireLoginProps> = ({
}, [profile])

useEffect(() => {
const { addToast } = toastyRef.current

if (loginRequiredForPath && initialStateLoaded && !profile) {
addToast(signInMessage, { variant: "primary" })
void router.push(signInPath)
Expand All @@ -73,7 +75,7 @@ const RequireLogin: FunctionComponent<RequireLoginProps> = ({
signInMessage,
termsPath,
hasTerms,
addToast,
toastyRef,
])

if (
Expand Down
2 changes: 1 addition & 1 deletion shared-helpers/src/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@
"authentication.forgotPassword.errors.passwordTooWeak": "La contraseña es demasiado débil. Debe tener al menos 12 caracteres e incluir al menos una letra minúscula, una letra mayúscula, un número y un carácter especial (#?!@$%^&*-).",
"authentication.forgotPassword.errors.tokenExpired": "El token de restablecimiento de contraseña caducó. Por favor, solicite uno nuevo.",
"authentication.forgotPassword.errors.tokenMissing": "El token no fue encontrado. Por favor, solicite uno nuevo.",
"authentication.forgotPassword.message": "Si hay una cuenta creada con ese correo electrónico, recibirás un correo electrónico con un enlace para restablecer tu contraseña.",
"authentication.forgotPassword.message": "Si hay una cuenta creada con ese correo electrónico, recibirás un correo electrónico con un enlace para restablecer tu contraseña. El enlace de reinicio es válido por 1 hora.",
"authentication.forgotPassword.passwordConfirmation": "Confirmación de contraseña",
"authentication.forgotPassword.sendEmail": "Enviar correo electrónico",
"authentication.signIn.accountHasBeenLocked": "Por razones de seguridad, esta cuenta ha sido bloqueada.",
Expand Down
2 changes: 1 addition & 1 deletion shared-helpers/src/locales/general.json
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@
"authentication.forgotPassword.errors.passwordTooWeak": "Password is too weak. Must be at least 12 characters and include at least one lowercase letter, one uppercase letter, one number, and one special character (#?!@$%^&*-).",
"authentication.forgotPassword.errors.tokenExpired": "Reset password token expired. Please request for a new one.",
"authentication.forgotPassword.errors.tokenMissing": "Token not found. Please request for a new one.",
"authentication.forgotPassword.message": "If there is an account made with that email, you'll receive an email with a link to reset your password.",
"authentication.forgotPassword.message": "If there is an account made with that email, you'll receive an email with a link to reset your password. The reset link is valid for 1 hour.",
"authentication.forgotPassword.passwordConfirmation": "Password Confirmation",
"authentication.forgotPassword.sendEmail": "Send email",
"authentication.signIn.accountHasBeenLocked": "For security reasons, this account has been locked.",
Expand Down
2 changes: 1 addition & 1 deletion shared-helpers/src/locales/tl.json
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@
"authentication.forgotPassword.errors.passwordTooWeak": "Masyadong mahina ang password. Dapat ay hindi bababa sa 12 character at may kasamang hindi bababa sa isang maliit na titik, isang malaking titik, isang numero, at isang espesyal na character (#?!@$%^&*-).",
"authentication.forgotPassword.errors.tokenExpired": "Nag-expire na ang token ng pag-reset ng password. Humiling ng bago.",
"authentication.forgotPassword.errors.tokenMissing": "Hindi nahanap ang token. Humiling ng bago.",
"authentication.forgotPassword.message": "Kung may account na ginawa gamit ang email na iyon, makakatanggap ka ng email na may link para i-reset ang iyong password.",
"authentication.forgotPassword.message": "Kung may account na ginawa gamit ang email na iyon, makakatanggap ka ng email na may link para i-reset ang iyong password. Ang link sa pag-reset ay may bisa sa loob ng 1 oras.",
"authentication.forgotPassword.passwordConfirmation": "Pagkumpirma ng Password",
"authentication.forgotPassword.sendEmail": "Magpadala ng email",
"authentication.signIn.accountHasBeenLocked": "Para sa mga kadahilanang pangseguridad, ang account na ito isinara na.",
Expand Down
2 changes: 1 addition & 1 deletion shared-helpers/src/locales/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@
"authentication.forgotPassword.errors.passwordTooWeak": "Mật khẩu quá yếu. Phải có ít nhất 12 ký tự và bao gồm ít nhất một chữ cái viết thường, một chữ cái viết hoa, một số và một ký tự đặc biệt (#?!@$%^&*-).",
"authentication.forgotPassword.errors.tokenExpired": "Mã thông báo đặt lại mật khẩu đã hết hạn. Vui lòng yêu cầu mã mới.",
"authentication.forgotPassword.errors.tokenMissing": "Không tìm thấy mã thông báo. Vui lòng yêu cầu mã mới.",
"authentication.forgotPassword.message": "Nếu có tài khoản được tạo bằng email đó, bạn sẽ nhận được email có liên kết để đặt lại mật khẩu của mình.",
"authentication.forgotPassword.message": "Nếu có tài khoản được tạo bằng email đó, bạn sẽ nhận được email có liên kết để đặt lại mật khẩu của mình. Liên kết đặt lại có hiệu lực trong 1 giờ.",
"authentication.forgotPassword.passwordConfirmation": "Xác nhận mật khẩu",
"authentication.forgotPassword.sendEmail": "Gửi email",
"authentication.signIn.accountHasBeenLocked": "Vì lý do bảo mật, tài khoản này đã bị khóa.",
Expand Down
2 changes: 1 addition & 1 deletion shared-helpers/src/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@
"authentication.forgotPassword.errors.passwordTooWeak": "密碼強度太弱。必須至少 12 個字符,並且至少包含 1 個小寫字母、1 個大寫字母、1 個數字和 1 個特殊字符 (#?!@$%^&*-)。",
"authentication.forgotPassword.errors.tokenExpired": "重設密碼權杖已到期。請要求新的權杖。",
"authentication.forgotPassword.errors.tokenMissing": "找不到權杖。請要求新的權杖。",
"authentication.forgotPassword.message": "如果使用该电子邮件创建了帐户,您将收到一封包含重置密码链接的电子邮件。",
"authentication.forgotPassword.message": "如果使用该电子邮件创建了帐户,您将收到一封包含重置密码链接的电子邮件。 重置链接有效期为1小时。",
"authentication.forgotPassword.passwordConfirmation": "确认密码",
"authentication.forgotPassword.sendEmail": "傳送電子郵件",
"authentication.signIn.accountHasBeenLocked": "基於安全原因,此帳戶已遭到鎖定。",
Expand Down
18 changes: 17 additions & 1 deletion shared-helpers/src/utilities/MessageContext.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import React, { FunctionComponent, createContext, createElement, useState, useRef } from "react"
import React, {
FunctionComponent,
createContext,
createElement,
useContext,
useState,
useRef,
} from "react"
import { CommonMessageProps } from "@bloom-housing/ui-seeds/src/blocks/shared/CommonMessage"

// TODO: this should be exportable from seeds directly
Expand Down Expand Up @@ -49,3 +56,12 @@ export const MessageProvider: FunctionComponent<React.PropsWithChildren> = ({ ch
children
)
}

/**
* Use the current value of a ref within `useEffect` so you can pass the ref to the dependencies
* array. Otherwise, the effect will constantly rerun because the context alone isn't a stable ref.
* File this one in the "Weird React" category!
*/
export const useToastyRef = () => {
return useRef(useContext(MessageContext))
}
11 changes: 6 additions & 5 deletions sites/public/src/components/account/ConfirmationModal.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { t, Form, Field } from "@bloom-housing/ui-components"
import { Button, Dialog } from "@bloom-housing/ui-seeds"
import { AuthContext, MessageContext, emailRegex } from "@bloom-housing/shared-helpers"
import { AuthContext, useToastyRef, emailRegex } from "@bloom-housing/shared-helpers"
import { useRouter } from "next/router"
import { useContext, useEffect, useRef, useState } from "react"
import { useForm } from "react-hook-form"
Expand All @@ -10,7 +10,7 @@ export interface ConfirmationModalProps {}

const ConfirmationModal = () => {
const { resendConfirmation, profile, confirmAccount } = useContext(AuthContext)
const { addToast } = useContext(MessageContext)
const toastyRef = useToastyRef()
const [openModal, setOpenModal] = useState(false)
const router = useRouter()

Expand All @@ -23,6 +23,8 @@ const ConfirmationModal = () => {
email.current = watch("email", "")

const onSubmit = async (email) => {
const { addToast } = toastyRef.current

try {
const listingId = router.query?.listingId as string
await resendConfirmation(email, listingId)
Expand All @@ -42,6 +44,7 @@ const ConfirmationModal = () => {
}

useEffect(() => {
const { addToast } = toastyRef.current
const redirectUrl = router.query?.redirectUrl as string
const listingId = router.query?.listingId as string

Expand Down Expand Up @@ -71,9 +74,7 @@ const ConfirmationModal = () => {
}
})
}
// This ensures useEffect is called only once
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [router, profile])
}, [router, profile, toastyRef])

return (
<Dialog
Expand Down
10 changes: 6 additions & 4 deletions sites/public/src/pages/applications/review/summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
PageView,
pushGtmEvent,
AuthContext,
MessageContext,
useToastyRef,
listingSectionQuestions,
} from "@bloom-housing/shared-helpers"
import {
Expand All @@ -29,7 +29,7 @@ import dayjs from "dayjs"
const ApplicationSummary = () => {
const router = useRouter()
const { profile, applicationsService } = useContext(AuthContext)
const { addToast } = useContext(MessageContext)
const toastyRef = useToastyRef()
const [validationError, setValidationError] = useState(false)
const { conductor, application, listing } = useFormConductor("summary")
let currentPageSection = 4
Expand All @@ -51,18 +51,20 @@ const ApplicationSummary = () => {
}, [profile])

useEffect(() => {
const { addToast } = toastyRef.current

if (listing && router.isReady) {
const currentDate = dayjs()
if (
!(listing.digitalApplication && listing.commonDigitalApplication) ||
listing?.status !== ListingsStatusEnum.active ||
(listing?.applicationDueDate && currentDate > dayjs(listing.applicationDueDate))
) {
// addToast(t("listings.applicationsClosedRedirect"), { variant: "alert" })
addToast(t("listings.applicationsClosedRedirect"), { variant: "alert" })
void router.push(`/${router.locale}/listing/${listing?.id}/${listing.urlSlug}`)
}
}
}, [listing, router, addToast])
}, [listing, router, toastyRef])

useEffect(() => {
conductor.application.reachedReviewStep = true
Expand Down
10 changes: 6 additions & 4 deletions sites/public/src/pages/applications/start/choose-language.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
PageView,
pushGtmEvent,
AuthContext,
MessageContext,
useToastyRef,
CustomIconMap,
} from "@bloom-housing/shared-helpers"
import {
Expand Down Expand Up @@ -54,7 +54,7 @@ const ApplicationChooseLanguage = () => {
const [listing, setListing] = useState(null)
const context = useContext(AppSubmissionContext)
const { initialStateLoaded, profile, listingsService } = useContext(AuthContext)
const { addToast } = useContext(MessageContext)
const toastyRef = useToastyRef()
const { conductor } = context

const listingId = router.query.listingId
Expand Down Expand Up @@ -86,18 +86,20 @@ const ApplicationChooseLanguage = () => {
}, [router, conductor, context, listingId, initialStateLoaded, profile, listingsService])

useEffect(() => {
const { addToast } = toastyRef.current

if (listing && router.isReady) {
const currentDate = dayjs()
if (
!(listing.digitalApplication && listing.commonDigitalApplication) ||
(router?.query?.preview !== "true" && listing?.status !== ListingsStatusEnum.active) ||
(listing?.applicationDueDate && currentDate > dayjs(listing.applicationDueDate))
) {
// addToast(t("listings.applicationsClosedRedirect"), { variant: "alert" })
addToast(t("listings.applicationsClosedRedirect"), { variant: "alert" })
void router.push(`/${router.locale}/listing/${listing?.id}/${listing?.urlSlug}`)
}
}
}, [listing, router, addToast])
}, [listing, router, toastyRef])

const imageUrl = listing?.assets
? imageUrlFromListing(listing, parseInt(process.env.listingPhotoSize))[0]
Expand Down

0 comments on commit 061c810

Please sign in to comment.