Skip to content

Commit

Permalink
New "none" handling and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
7emansell committed Dec 12, 2024
1 parent fded8cb commit f1a778f
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 89 deletions.
4 changes: 3 additions & 1 deletion src/components/MyAccount/Settings/EditButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ type EditButtonProps = {
buttonId: string
buttonLabel: string
onClick: () => void
isDisabled?: boolean
}

const EditButton = forwardRef<HTMLButtonElement, EditButtonProps>(
({ buttonLabel, buttonId, onClick }, ref) => {
({ buttonLabel, buttonId, isDisabled, onClick }, ref) => {
return (
<Button
ref={ref}
isDisabled={isDisabled}
id={buttonId}
aria-label={buttonLabel}
buttonType="text"
Expand Down
156 changes: 100 additions & 56 deletions src/components/MyAccount/Settings/NotificationForm.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { render, screen, fireEvent, waitFor } from "@testing-library/react"
import { filteredPickupLocations } from "../../../../__test__/fixtures/processedMyAccountData"
import { PatronDataProvider } from "../../../context/PatronDataContext"
import { processedPatron } from "../../../../__test__/fixtures/processedMyAccountData"
import {
processedPatron,
emptyPatron,
} from "../../../../__test__/fixtures/processedMyAccountData"
import { pickupLocations } from "../../../../__test__/fixtures/rawSierraAccountData"
import SettingsSelectForm from "./SettingsSelectForm"
import type { Patron } from "../../../types/myAccountTypes"
Expand Down Expand Up @@ -34,33 +37,79 @@ describe("notification preference form", () => {
(pref) => pref.code === processedPatron.notificationPreference
)?.name

const component = (
<PatronDataProvider
testSpy={accountFetchSpy}
value={{
patron: processedPatron,
pickupLocations: filteredPickupLocations,
}}
>
<SettingsSelectForm
patronData={processedPatron}
settingsState={mockSettingsState}
pickupLocations={pickupLocations}
type="notification"
/>
</PatronDataProvider>
)
const processedPatronWithNone = {
notificationPreference: "-",
username: "pastadisciple",
name: "Strega Nonna",
barcode: "23333121538324",
formattedBarcode: "2 3333 12153 8324",
expirationDate: "March 28, 2025",
emails: ["[email protected]", "[email protected]"],
phones: [
{
number: "123-456-7890",
type: "t",
},
],
homeLibrary: { code: "sn ", name: "SNFL (formerly Mid-Manhattan)" },
id: 6742743,
} as Patron

const processedPatronWithNothing = {
notificationPreference: "-",
username: "pastadisciple",
name: "Strega Nonna",
barcode: "23333121538324",
formattedBarcode: "2 3333 12153 8324",
expirationDate: "March 28, 2025",
emails: [],
phones: [],
homeLibrary: { code: "sn ", name: "SNFL (formerly Mid-Manhattan)" },
id: 6742743,
} as Patron

const processedPatronWithNoPhone = {
notificationPreference: "-",
username: "pastadisciple",
name: "Strega Nonna",
barcode: "23333121538324",
formattedBarcode: "2 3333 12153 8324",
expirationDate: "March 28, 2025",
emails: ["[email protected]", "[email protected]"],
phones: [],
homeLibrary: { code: "sn ", name: "SNFL (formerly Mid-Manhattan)" },
id: 6742743,
} as Patron

const component = (patron) => {
return (
<PatronDataProvider
testSpy={accountFetchSpy}
value={{
patron: patron,
pickupLocations: filteredPickupLocations,
}}
>
<SettingsSelectForm
patronData={patron}
settingsState={mockSettingsState}
pickupLocations={pickupLocations}
type="notification"
/>
</PatronDataProvider>
)
}

it("renders correctly with initial preference", () => {
render(component)
render(component(processedPatron))

expect(screen.getByText(processedPatronPref)).toBeInTheDocument()

expect(screen.getByRole("button", { name: /edit/i })).toBeInTheDocument()
})

it("allows editing when edit button is clicked", () => {
render(component)
render(component(processedPatron))
fireEvent.click(screen.getByRole("button", { name: /edit/i }))

expect(
Expand All @@ -78,7 +127,7 @@ describe("notification preference form", () => {
})

it("manages focus", async () => {
render(component)
render(component(processedPatron))
fireEvent.click(screen.getByRole("button", { name: /edit/i }))

await waitFor(() => expect(screen.getByRole("combobox")).toHaveFocus())
Expand All @@ -90,8 +139,36 @@ describe("notification preference form", () => {
)
})

it("disables editing the none preference when user has no phone or email", () => {
render(component(processedPatronWithNothing))

expect(screen.getByLabelText("Edit notification")).toBeInTheDocument()

expect(screen.getByLabelText("Edit notification")).toBeDisabled()

expect(screen.getByText("None")).toBeInTheDocument()

expect(
screen.getByText(
"Please set a phone number or email address to choose a notification preference."
)
).toBeInTheDocument()
})

it("disables the corresponding dropdown field when user doesn't have that contact method", () => {
render(component(processedPatronWithNoPhone))

fireEvent.click(screen.getByRole("button", { name: /edit/i }))

const phoneOption = screen.getByRole("option", { name: "Phone" })
expect(phoneOption).toBeDisabled()

const emailOption = screen.getByRole("option", { name: "Email" })
expect(emailOption).not.toBeDisabled()
})

it("calls submit with valid data", async () => {
render(component)
render(component(processedPatron))

fireEvent.click(screen.getByRole("button", { name: /edit/i }))

Expand All @@ -116,48 +193,15 @@ describe("notification preference form", () => {
})

it("displays none as an option if that's already user's selection", async () => {
const processedPatronWithNone = {
notificationPreference: "-",
username: "pastadisciple",
name: "Strega Nonna",
barcode: "23333121538324",
formattedBarcode: "2 3333 12153 8324",
expirationDate: "March 28, 2025",
emails: ["[email protected]", "[email protected]"],
phones: [
{
number: "123-456-7890",
type: "t",
},
],
homeLibrary: { code: "sn ", name: "SNFL (formerly Mid-Manhattan)" },
id: 6742743,
} as Patron
const component = (
<PatronDataProvider
testSpy={accountFetchSpy}
value={{
patron: processedPatronWithNone,
pickupLocations: filteredPickupLocations,
}}
>
<SettingsSelectForm
patronData={processedPatronWithNone}
settingsState={mockSettingsState}
pickupLocations={pickupLocations}
type="notification"
/>
</PatronDataProvider>
)
render(component)
render(component(processedPatronWithNone))

fireEvent.click(screen.getByRole("button", { name: /edit/i }))

expect(screen.getByText("None")).toBeInTheDocument()
})

it("cancels editing and reverts state", () => {
render(component)
render(component(processedPatron))

fireEvent.click(screen.getByRole("button", { name: /edit/i }))

Expand Down
23 changes: 12 additions & 11 deletions src/components/MyAccount/Settings/SettingsInputForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ const SettingsInputForm = ({
<div style={{ width: "72px" }}> </div>
</Flex>
</Flex>
) : isEmail || tempInputs.length !== 0 ? (
) : tempInputs.length !== 0 ? (
<Flex
marginLeft={{ base: "m", lg: "unset" }}
flexDir="row"
Expand Down Expand Up @@ -292,23 +292,24 @@ const SettingsInputForm = ({
onClick={() => {
setIsEditing(true)
setEditingField(inputType)
console.log("hello")
setTimeout(() => focusFirstInput(), 0)
}}
/>
)}
</Flex>
) : (
// User has no phone or email.
<AddButton
inputType={inputType}
onClick={() => {
setIsEditing(true)
setEditingField(inputType)
handleAdd()
}}
label={formUtils.addButtonLabel}
/>
<Box sx={{ marginTop: { base: "unset", lg: "-xs" } }}>
<AddButton
inputType={inputType}
onClick={() => {
setIsEditing(true)
setEditingField(inputType)
handleAdd()
}}
label={formUtils.addButtonLabel}
/>
</Box>
)}

{isEditing && (
Expand Down
73 changes: 52 additions & 21 deletions src/components/MyAccount/Settings/SettingsSelectForm.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useContext, useRef, useState } from "react"
import { PatronDataContext } from "../../../context/PatronDataContext"
import {
Banner,
Flex,
Select,
SkeletonLoader,
Expand Down Expand Up @@ -33,17 +34,20 @@ const SettingsSelectForm = ({
const selectRef = useRef<HTMLSelectElement | null>()
const editingRef = useRef<HTMLButtonElement | null>()

const notificationPreferenceMap =
patronData.notificationPreference === "-"
? [
{ code: "z", name: "Email" },
{ code: "p", name: "Phone" },
{ code: "-", name: "None" },
]
: [
{ code: "z", name: "Email" },
{ code: "p", name: "Phone" },
]
const patronHasNonePref = patronData.notificationPreference === "-"
const patronHasPhone = patronData.phones.length > 0
const patronHasEmail = patronData.emails.length > 0

const notificationPreferenceMap = patronHasNonePref
? [
{ code: "z", name: "Email" },
{ code: "p", name: "Phone" },
{ code: "-", name: "None" },
]
: [
{ code: "z", name: "Email" },
{ code: "p", name: "Phone" },
]

const sortedPickupLocations = [
patronData.homeLibrary,
Expand Down Expand Up @@ -174,25 +178,52 @@ const SettingsSelectForm = ({
value={tempSelection}
>
{formUtils.options.map((option, index) => (
<option key={`${type}-option-${index}`} value={option.name}>
<option
key={`${type}-option-${index}`}
value={option.name}
disabled={
(option.name === "Email" && !patronHasEmail) ||
(option.name === "Phone" && !patronHasPhone)
}
>
{option.name}
</option>
))}
</Select>
</Flex>
) : (
<Flex marginLeft={{ base: "m", lg: "unset" }}>
<Text
sx={{
marginTop: { base: "xs", lg: "unset" },
width: { base: "200px", sm: "250px" },
marginBottom: 0,
}}
>
{selection}
</Text>
<Flex flexDir="column">
<Text
sx={{
marginTop: { base: "xs", lg: "unset" },
width: { base: "200px", sm: "250px" },
marginBottom: 0,
}}
>
{selection}
</Text>
{type === "notification" &&
patronHasNonePref &&
!patronHasPhone &&
!patronHasEmail && (
<Banner
sx={{
marginTop: "s",
width: { base: "200px", sm: "250px" },
}}
content="Please set a phone number or email address to choose a notification preference."
/>
)}
</Flex>
{editingField === "" && (
<EditButton
isDisabled={
type === "notification" &&
patronHasNonePref &&
!patronHasPhone &&
!patronHasEmail
}
ref={editingRef}
buttonLabel={`Edit ${type}`}
buttonId={`edit-${type}-button`}
Expand Down

0 comments on commit f1a778f

Please sign in to comment.