Files
web/components/Forms/Edit/Profile/index.tsx
Pontus Dreij 76cd1945c4 Merged in feat(SW-1677)-my-stay-update-contact-user (pull request #1386)
Feat(SW-1677) my stay update contact user

* feat(SW-1677): Hide membersettings that doesnt match the booking

* feat(SW-1677) Edit my stay contact details as user


Approved-by: Linus Flood
2025-02-24 11:31:19 +00:00

179 lines
5.4 KiB
TypeScript

"use client"
import { zodResolver } from "@hookform/resolvers/zod"
import { isValidPhoneNumber, parsePhoneNumber } from "libphonenumber-js"
import { useParams, useRouter } from "next/navigation"
import { useEffect, useState } from "react"
import { FormProvider, useForm } from "react-hook-form"
import { usePhoneInput } from "react-international-phone"
import { useIntl } from "react-intl"
import { type Lang, langToApiLang } from "@/constants/languages"
import { logout } from "@/constants/routes/handleAuth"
import { profile } from "@/constants/routes/myPages"
import { trpc } from "@/lib/trpc/client"
import { editProfile } from "@/actions/editProfile"
import Dialog from "@/components/Dialog"
import Button from "@/components/TempDesignSystem/Button"
import Title from "@/components/TempDesignSystem/Text/Title"
import { toast } from "@/components/TempDesignSystem/Toasts"
import FormContent from "./FormContent"
import { type EditProfileSchema, editProfileSchema } from "./schema"
import styles from "./form.module.css"
import {
type EditFormProps,
Status,
} from "@/types/components/myPages/myProfile/edit"
const formId = "edit-profile"
export default function Form({ user }: EditFormProps) {
const intl = useIntl()
const router = useRouter()
const params = useParams()
const lang = params.lang as Lang
const utils = trpc.useUtils()
/**
* RHF isValid defaults to false and never
* changes when JS is disabled, therefore
* we need to keep it insync ourselves
*/
const [isValid, setIsValid] = useState(true)
const { inputValue: phoneInput } = usePhoneInput({
defaultCountry:
user.phoneNumber && isValidPhoneNumber(user.phoneNumber)
? parsePhoneNumber(user.phoneNumber).country?.toLowerCase()
: "se",
forceDialCode: true,
value: user.phoneNumber,
})
const methods = useForm<EditProfileSchema>({
defaultValues: {
address: {
city: user.address?.city ?? "",
countryCode: user.address?.countryCode ?? "",
streetAddress: user.address?.streetAddress ?? "",
zipCode: user.address?.zipCode ?? "",
},
dateOfBirth: user.dateOfBirth,
email: user.email,
language: user.language ?? langToApiLang[lang],
phoneNumber: phoneInput,
password: "",
newPassword: "",
retypeNewPassword: "",
},
mode: "all",
criteriaMode: "all",
resolver: zodResolver(editProfileSchema),
reValidateMode: "onChange",
})
const trigger = methods.trigger
async function handleSubmit(data: EditProfileSchema) {
const isPasswordChanged = !!data.newPassword
const response = await editProfile(data)
switch (response.status) {
case Status.error:
if (response.issues?.length) {
response.issues.forEach((issue) => {
console.error(issue)
})
}
toast.error(response.message)
break
case Status.success:
toast.success(response.message)
utils.user.get.invalidate()
if (isPasswordChanged) {
// Kept logout out of Next router forcing browser to navigate on logout url
window.location.href = logout[lang]
} else {
const myStayReturnRoute = localStorage.getItem("myStayReturnRoute")
if (myStayReturnRoute) {
const returnRoute = JSON.parse(myStayReturnRoute)
localStorage.removeItem("myStayReturnRoute")
router.push(returnRoute.path)
} else {
router.push(profile[lang])
}
router.refresh() // Can be removed on NextJs 15
}
break
}
}
useEffect(() => {
setIsValid(methods.formState.isValid)
}, [setIsValid, methods.formState.isValid])
useEffect(() => {
trigger()
}, [trigger])
return (
<section className={styles.container}>
<div className={styles.title}>
<Title as="h4" color="red" level="h1" textTransform="capitalize">
{intl.formatMessage({ id: "Welcome" })}
</Title>
<Title
data-hj-suppress
as="h4"
color="burgundy"
level="h2"
textTransform="capitalize"
>
{user.name}
</Title>
</div>
<div className={styles.btnContainer}>
<Dialog
bodyText={intl.formatMessage({
id: "Any changes you've made will be lost.",
})}
cancelButtonText={intl.formatMessage({ id: "Go back to edit" })}
proceedHref={profile[lang]}
proceedText={intl.formatMessage({ id: "Yes, discard changes" })}
titleText={intl.formatMessage({ id: "Discard unsaved changes?" })}
trigger={
<Button intent="secondary" size="small" theme="base">
{intl.formatMessage({ id: "Discard changes" })}
</Button>
}
/>
<Button
disabled={!isValid || methods.formState.isSubmitting}
form={formId}
intent="primary"
size="small"
theme="base"
type="submit"
>
{intl.formatMessage({ id: "Save" })}
</Button>
</div>
<form
/**
* Ignoring since ts doesn't recognize that tRPC
* parses FormData before reaching the route
* @ts-ignore */
action={editProfile}
className={styles.form}
id={formId}
onSubmit={methods.handleSubmit(handleSubmit)}
>
<FormProvider {...methods}>
<FormContent />
</FormProvider>
</form>
</section>
)
}