fix: use zod in getting started and settings (#7698)
* fix: use zod in getting started and settings Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * chore: change name of variable Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> --------- Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> Co-authored-by: Bailey Pumfleet <bailey@pumfleet.co.uk>pull/7852/head^2
parent
db947591ad
commit
7af23305eb
|
@ -1,8 +1,11 @@
|
||||||
import { ArrowRightIcon } from "@heroicons/react/outline";
|
import { ArrowRightIcon } from "@heroicons/react/outline";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
import dayjs from "@calcom/dayjs";
|
import dayjs from "@calcom/dayjs";
|
||||||
|
import { FULL_NAME_LENGTH_MAX_LIMIT } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
|
@ -22,23 +25,30 @@ const UserSettings = (props: IUserSettingsProps) => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const [selectedTimeZone, setSelectedTimeZone] = useState(dayjs.tz.guess());
|
const [selectedTimeZone, setSelectedTimeZone] = useState(dayjs.tz.guess());
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
const userSettingsSchema = z.object({
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.max(FULL_NAME_LENGTH_MAX_LIMIT, {
|
||||||
|
message: t("max_limit_allowed_hint", { limit: FULL_NAME_LENGTH_MAX_LIMIT }),
|
||||||
|
}),
|
||||||
|
});
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { errors },
|
formState: { errors },
|
||||||
} = useForm({
|
} = useForm<z.infer<typeof userSettingsSchema>>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: user?.name || "",
|
name: user?.name || "",
|
||||||
},
|
},
|
||||||
reValidateMode: "onChange",
|
reValidateMode: "onChange",
|
||||||
|
resolver: zodResolver(userSettingsSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
telemetry.event(telemetryEventTypes.onboardingStarted);
|
telemetry.event(telemetryEventTypes.onboardingStarted);
|
||||||
}, [telemetry]);
|
}, [telemetry]);
|
||||||
|
|
||||||
const defaultOptions = { required: true, maxLength: 255 };
|
|
||||||
|
|
||||||
const utils = trpc.useContext();
|
const utils = trpc.useContext();
|
||||||
const onSuccess = async () => {
|
const onSuccess = async () => {
|
||||||
await utils.viewer.me.invalidate();
|
await utils.viewer.me.invalidate();
|
||||||
|
@ -67,7 +77,9 @@ const UserSettings = (props: IUserSettingsProps) => {
|
||||||
{t("full_name")}
|
{t("full_name")}
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
{...register("name", defaultOptions)}
|
{...register("name", {
|
||||||
|
required: true,
|
||||||
|
})}
|
||||||
id="name"
|
id="name"
|
||||||
name="name"
|
name="name"
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -77,7 +89,7 @@ const UserSettings = (props: IUserSettingsProps) => {
|
||||||
/>
|
/>
|
||||||
{errors.name && (
|
{errors.name && (
|
||||||
<p data-testid="required" className="py-2 text-xs text-red-500">
|
<p data-testid="required" className="py-2 text-xs text-red-500">
|
||||||
{t("required")}
|
{errors.name.message}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { IdentityProvider } from "@prisma/client";
|
import { IdentityProvider } from "@prisma/client";
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import { signOut } from "next-auth/react";
|
import { signOut } from "next-auth/react";
|
||||||
import type { BaseSyntheticEvent } from "react";
|
import type { BaseSyntheticEvent } from "react";
|
||||||
import { useRef, useState } from "react";
|
import { useRef, useState } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode";
|
import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode";
|
||||||
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
|
||||||
|
import { FULL_NAME_LENGTH_MAX_LIMIT } from "@calcom/lib/constants";
|
||||||
import { APP_NAME } from "@calcom/lib/constants";
|
import { APP_NAME } from "@calcom/lib/constants";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { md } from "@calcom/lib/markdownIt";
|
import { md } from "@calcom/lib/markdownIt";
|
||||||
|
@ -315,6 +318,20 @@ const ProfileForm = ({
|
||||||
extraField?: React.ReactNode;
|
extraField?: React.ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
|
|
||||||
|
const profileFormSchema = z.object({
|
||||||
|
username: z.string(),
|
||||||
|
avatar: z.string(),
|
||||||
|
name: z
|
||||||
|
.string()
|
||||||
|
.min(1)
|
||||||
|
.max(FULL_NAME_LENGTH_MAX_LIMIT, {
|
||||||
|
message: t("max_limit_allowed_hint", { limit: FULL_NAME_LENGTH_MAX_LIMIT }),
|
||||||
|
}),
|
||||||
|
email: z.string().email(),
|
||||||
|
bio: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
const emailMd5 = crypto
|
const emailMd5 = crypto
|
||||||
.createHash("md5")
|
.createHash("md5")
|
||||||
.update(defaultValues.email || "example@example.com")
|
.update(defaultValues.email || "example@example.com")
|
||||||
|
@ -322,6 +339,7 @@ const ProfileForm = ({
|
||||||
|
|
||||||
const formMethods = useForm<FormValues>({
|
const formMethods = useForm<FormValues>({
|
||||||
defaultValues,
|
defaultValues,
|
||||||
|
resolver: zodResolver(profileFormSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -432,6 +432,7 @@
|
||||||
"password_hint_min": "Minimum 7 characters long",
|
"password_hint_min": "Minimum 7 characters long",
|
||||||
"password_hint_admin_min": "Minimum 15 characters long",
|
"password_hint_admin_min": "Minimum 15 characters long",
|
||||||
"password_hint_num": "Contain at least 1 number",
|
"password_hint_num": "Contain at least 1 number",
|
||||||
|
"max_limit_allowed_hint":"Must be {{limit}} or fewer characters long",
|
||||||
"invalid_password_hint": "The password must be a minimum of {{passwordLength}} characters long containing at least one number and have a mixture of uppercase and lowercase letters",
|
"invalid_password_hint": "The password must be a minimum of {{passwordLength}} characters long containing at least one number and have a mixture of uppercase and lowercase letters",
|
||||||
"incorrect_password": "Password is incorrect.",
|
"incorrect_password": "Password is incorrect.",
|
||||||
"incorrect_username_password": "Username or password is incorrect.",
|
"incorrect_username_password": "Username or password is incorrect.",
|
||||||
|
|
|
@ -62,3 +62,4 @@ export const IS_STRIPE_ENABLED = !!(
|
||||||
);
|
);
|
||||||
/** Self hosted shouldn't checkout when creating teams unless required */
|
/** Self hosted shouldn't checkout when creating teams unless required */
|
||||||
export const IS_TEAM_BILLING_ENABLED = IS_STRIPE_ENABLED && (!IS_SELF_HOSTED || HOSTED_CAL_FEATURES);
|
export const IS_TEAM_BILLING_ENABLED = IS_STRIPE_ENABLED && (!IS_SELF_HOSTED || HOSTED_CAL_FEATURES);
|
||||||
|
export const FULL_NAME_LENGTH_MAX_LIMIT = 50;
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { samlTenantProduct } from "@calcom/features/ee/sso/lib/saml";
|
||||||
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
|
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
|
||||||
import getEnabledApps from "@calcom/lib/apps/getEnabledApps";
|
import getEnabledApps from "@calcom/lib/apps/getEnabledApps";
|
||||||
import { IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
|
import { IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
import { FULL_NAME_LENGTH_MAX_LIMIT } from "@calcom/lib/constants";
|
||||||
import { symmetricDecrypt } from "@calcom/lib/crypto";
|
import { symmetricDecrypt } from "@calcom/lib/crypto";
|
||||||
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
||||||
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
|
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
|
||||||
|
@ -595,7 +596,7 @@ const loggedInViewerRouter = router({
|
||||||
.input(
|
.input(
|
||||||
z.object({
|
z.object({
|
||||||
username: z.string().optional(),
|
username: z.string().optional(),
|
||||||
name: z.string().optional(),
|
name: z.string().max(FULL_NAME_LENGTH_MAX_LIMIT).optional(),
|
||||||
email: z.string().optional(),
|
email: z.string().optional(),
|
||||||
bio: z.string().optional(),
|
bio: z.string().optional(),
|
||||||
avatar: z.string().optional(),
|
avatar: z.string().optional(),
|
||||||
|
|
Loading…
Reference in New Issue