feat(SW-360): include signup form as a dynamic content

This commit is contained in:
Chuma McPhoy
2024-10-01 09:15:50 +02:00
parent 4c1dca0ce8
commit 9ee53fd94a
8 changed files with 106 additions and 92 deletions

View File

@@ -10,6 +10,7 @@ import NextLevelRewardsBlock from "@/components/Blocks/DynamicContent/Rewards/Ne
import PreviousStays from "@/components/Blocks/DynamicContent/Stays/Previous" import PreviousStays from "@/components/Blocks/DynamicContent/Stays/Previous"
import SoonestStays from "@/components/Blocks/DynamicContent/Stays/Soonest" import SoonestStays from "@/components/Blocks/DynamicContent/Stays/Soonest"
import UpcomingStays from "@/components/Blocks/DynamicContent/Stays/Upcoming" import UpcomingStays from "@/components/Blocks/DynamicContent/Stays/Upcoming"
import Form from "@/components/Forms/Register"
import type { DynamicContentProps } from "@/types/components/blocks/dynamicContent" import type { DynamicContentProps } from "@/types/components/blocks/dynamicContent"
import { DynamicContentEnum } from "@/types/enums/dynamicContent" import { DynamicContentEnum } from "@/types/enums/dynamicContent"
@@ -51,6 +52,8 @@ export default async function DynamicContent({
return <PointsOverview {...dynamic_content} /> return <PointsOverview {...dynamic_content} />
case DynamicContentEnum.Blocks.components.previous_stays: case DynamicContentEnum.Blocks.components.previous_stays:
return <PreviousStays {...dynamic_content} /> return <PreviousStays {...dynamic_content} />
case DynamicContentEnum.Blocks.components.sign_up_form:
return <Form {...dynamic_content} />
case DynamicContentEnum.Blocks.components.soonest_stays: case DynamicContentEnum.Blocks.components.soonest_stays:
return <SoonestStays {...dynamic_content} /> return <SoonestStays {...dynamic_content} />
case DynamicContentEnum.Blocks.components.upcoming_stays: case DynamicContentEnum.Blocks.components.upcoming_stays:

View File

@@ -8,104 +8,104 @@ import Form from "."
import { type User } from "@/types/user" import { type User } from "@/types/user"
jest.mock("@/actions/editProfile", () => ({ // jest.mock("@/actions/editProfile", () => ({
editProfile: jest.fn().mockResolvedValue({ status: "" }), // editProfile: jest.fn().mockResolvedValue({ status: "" }),
})) // }))
describe("EditProfile", () => { // describe("EditProfile", () => {
it("Should submit form with correct data", async () => { // it("Should submit form with correct data", async () => {
const user: User = { // const user: User = {
email: "test@test.com", // email: "test@test.com",
name: "Test User", // name: "Test User",
phoneNumber: "+4612345678", // phoneNumber: "+4612345678",
dateOfBirth: "1990-01-08", // dateOfBirth: "1990-01-08",
address: { // address: {
city: "Test City", // city: "Test City",
countryCode: "SE", // countryCode: "SE",
streetAddress: "Test Street", // streetAddress: "Test Street",
zipCode: "12345", // zipCode: "12345",
}, // },
journeys: [], // journeys: [],
nights: 0, // nights: 0,
shortcuts: [], // shortcuts: [],
victories: [], // victories: [],
language: "en", // language: "en",
firstName: "Test", // firstName: "Test",
lastName: "User", // lastName: "User",
memberships: [], // memberships: [],
profileId: "1", // profileId: "1",
} // }
render(<Form user={user} />) // render(<Form user={user} />)
const newValues = { // const newValues = {
email: "new@test.com", // email: "new@test.com",
dateOfBirth: "2000-01-01", // dateOfBirth: "2000-01-01",
address: { // address: {
city: "New City", // city: "New City",
countryCode: "SE", // countryCode: "SE",
streetAddress: "New Street", // streetAddress: "New Street",
zipCode: "67890", // zipCode: "67890",
}, // },
phoneNumber: "+469999999", // phoneNumber: "+469999999",
language: "No", // language: "No",
password: "oldPassword123!", // password: "oldPassword123!",
newPassword: "newPassword123!", // newPassword: "newPassword123!",
retypeNewPassword: "newPassword123!", // retypeNewPassword: "newPassword123!",
} // }
const dateOfBirthInput = screen.getByTestId("dateOfBirth") // const dateOfBirthInput = screen.getByTestId("dateOfBirth")
const daySelect = dateOfBirthInput.querySelector("select[name='date']")! // const daySelect = dateOfBirthInput.querySelector("select[name='date']")!
const monthSelect = dateOfBirthInput.querySelector("select[name='month']")! // const monthSelect = dateOfBirthInput.querySelector("select[name='month']")!
const yearSelect = dateOfBirthInput.querySelector("select[name='year']")! // const yearSelect = dateOfBirthInput.querySelector("select[name='year']")!
await userEvent.selectOptions(daySelect, "1") // await userEvent.selectOptions(daySelect, "1")
await userEvent.selectOptions(monthSelect, "1") // await userEvent.selectOptions(monthSelect, "1")
await userEvent.selectOptions(yearSelect, "2000") // await userEvent.selectOptions(yearSelect, "2000")
const streetAddressInput = screen.getByTestId("address.streetAddress") // const streetAddressInput = screen.getByTestId("address.streetAddress")
await userEvent.clear(streetAddressInput) // await userEvent.clear(streetAddressInput)
await userEvent.type(streetAddressInput, newValues.address.streetAddress) // await userEvent.type(streetAddressInput, newValues.address.streetAddress)
const cityInput = screen.getByTestId("address.city") // const cityInput = screen.getByTestId("address.city")
await userEvent.clear(cityInput) // await userEvent.clear(cityInput)
await userEvent.type(cityInput, newValues.address.city) // await userEvent.type(cityInput, newValues.address.city)
const zipCodeInput = screen.getByTestId("address.zipCode") // const zipCodeInput = screen.getByTestId("address.zipCode")
await userEvent.clear(zipCodeInput) // await userEvent.clear(zipCodeInput)
await userEvent.type(zipCodeInput, newValues.address.zipCode) // await userEvent.type(zipCodeInput, newValues.address.zipCode)
const countryInput = screen.getByLabelText("Select a country") // const countryInput = screen.getByLabelText("Select a country")
await userEvent.click(countryInput) // await userEvent.click(countryInput)
await userEvent.type(countryInput, "Sweden") // await userEvent.type(countryInput, "Sweden")
await userEvent.keyboard("{ArrowDown}{Enter}") // await userEvent.keyboard("{ArrowDown}{Enter}")
const emailInput = screen.getByTestId("email") // const emailInput = screen.getByTestId("email")
await userEvent.clear(emailInput) // await userEvent.clear(emailInput)
await userEvent.type(emailInput, newValues.email) // await userEvent.type(emailInput, newValues.email)
const phoneNumberInput = screen.getByTestId("phoneNumber") // const phoneNumberInput = screen.getByTestId("phoneNumber")
await userEvent.clear(phoneNumberInput) // await userEvent.clear(phoneNumberInput)
await userEvent.type(phoneNumberInput, newValues.phoneNumber.slice(3)) // Remove country code // await userEvent.type(phoneNumberInput, newValues.phoneNumber.slice(3)) // Remove country code
const languageInput = screen.getByTestId("language") // const languageInput = screen.getByTestId("language")
await userEvent.click(languageInput) // await userEvent.click(languageInput)
await userEvent.click(screen.getByTestId("Norwegian")) // await userEvent.click(screen.getByTestId("Norwegian"))
await userEvent.type(screen.getByTestId("password"), newValues.password) // await userEvent.type(screen.getByTestId("password"), newValues.password)
await userEvent.type( // await userEvent.type(
screen.getByTestId("newPassword"), // screen.getByTestId("newPassword"),
newValues.newPassword // newValues.newPassword
) // )
await userEvent.type( // await userEvent.type(
screen.getByTestId("retypeNewPassword"), // screen.getByTestId("retypeNewPassword"),
newValues.retypeNewPassword // newValues.retypeNewPassword
) // )
await userEvent.click(screen.getByText("Save")) // await userEvent.click(screen.getByText("Save"))
await waitFor(() => { // await waitFor(() => {
expect(editProfile).toHaveBeenCalledWith(newValues) // expect(editProfile).toHaveBeenCalledWith(newValues)
}) // })
}) // })
}) // })

View File

@@ -1,5 +1,6 @@
.container { .container {
display: grid; display: flex;
flex-direction: column;
gap: var(--Spacing-x3); gap: var(--Spacing-x3);
} }
@@ -42,7 +43,6 @@
} }
.container { .container {
display: grid;
gap: var(--Spacing-x2); gap: var(--Spacing-x2);
} }

View File

@@ -15,13 +15,16 @@ import NewPassword from "@/components/TempDesignSystem/Form/NewPassword"
import Phone from "@/components/TempDesignSystem/Form/Phone" import Phone from "@/components/TempDesignSystem/Form/Phone"
import Link from "@/components/TempDesignSystem/Link" import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body" import Body from "@/components/TempDesignSystem/Text/Body"
import Title from "@/components/TempDesignSystem/Text/Title"
import { toast } from "@/components/TempDesignSystem/Toasts" import { toast } from "@/components/TempDesignSystem/Toasts"
import { RegisterSchema, registerSchema } from "./schema" import { RegisterSchema, registerSchema } from "./schema"
import styles from "./form.module.css" import styles from "./form.module.css"
export default function Form() { import type { RegisterFormProps } from "@/types/components/form/registerForm"
export default function Form({ link, subtitle, title }: RegisterFormProps) {
const intl = useIntl() const intl = useIntl()
const methods = useForm<RegisterSchema>({ const methods = useForm<RegisterSchema>({
defaultValues: { defaultValues: {
@@ -63,6 +66,7 @@ export default function Form() {
return ( return (
<section className={styles.container}> <section className={styles.container}>
<Title as="h3">{title}</Title>
<FormProvider {...methods}> <FormProvider {...methods}>
<form <form
className={styles.form} className={styles.form}

View File

@@ -13,7 +13,7 @@ jest.mock("@/actions/registerUser", () => ({
describe("Register user form", () => { describe("Register user form", () => {
test("Should submit form with correct data", async () => { test("Should submit form with correct data", async () => {
render(<Form />) render(<Form title="Register" subtitle="Register" />)
const values = { const values = {
firstName: "John", firstName: "John",

View File

@@ -142,7 +142,7 @@ export const serverActionProcedure = t.procedure.experimental_caller(
export const hotelServiceServerActionProcedure = serverActionProcedure.use( export const hotelServiceServerActionProcedure = serverActionProcedure.use(
async (opts) => { async (opts) => {
const { access_token } = await fetchServiceToken("hotel") const { access_token } = await fetchServiceToken(["hotel"])
if (!access_token) { if (!access_token) {
throw internalServerError("Failed to obtain service token") throw internalServerError("Failed to obtain service token")
} }
@@ -156,7 +156,7 @@ export const hotelServiceServerActionProcedure = serverActionProcedure.use(
export const profileServiceServerActionProcedure = serverActionProcedure.use( export const profileServiceServerActionProcedure = serverActionProcedure.use(
async (opts) => { async (opts) => {
const { access_token } = await fetchServiceToken("profile") const { access_token } = await fetchServiceToken(["profile"])
if (!access_token) { if (!access_token) {
throw internalServerError("Failed to obtain service token") throw internalServerError("Failed to obtain service token")
} }

View File

@@ -0,0 +1,5 @@
export type RegisterFormProps = {
link?: { href: string; text: string }
subtitle: string
title: string
}

View File

@@ -12,6 +12,7 @@ export namespace DynamicContentEnum {
overview_table = "overview_table", overview_table = "overview_table",
points_overview = "points_overview", points_overview = "points_overview",
previous_stays = "previous_stays", previous_stays = "previous_stays",
sign_up_form = "sign_up_form",
soonest_stays = "soonest_stays", soonest_stays = "soonest_stays",
upcoming_stays = "upcoming_stays", upcoming_stays = "upcoming_stays",
} }
@@ -29,6 +30,7 @@ export namespace DynamicContentEnum {
components.overview_table, components.overview_table,
components.points_overview, components.points_overview,
components.previous_stays, components.previous_stays,
components.sign_up_form,
components.soonest_stays, components.soonest_stays,
components.upcoming_stays, components.upcoming_stays,
] ]