import crypto from "crypto"; import { GetServerSidePropsContext } from "next"; import { serverSideTranslations } from "next-i18next/serverSideTranslations"; import { RefObject, useEffect, useRef, useState } from "react"; import Select from "react-select"; import TimezoneSelect from "react-timezone-select"; import { asStringOrUndefined } from "@lib/asStringOrNull"; import { getSession } from "@lib/auth"; import { extractLocaleInfo, localeLabels, localeOptions, OptionType } from "@lib/core/i18n/i18n.utils"; import { useLocale } from "@lib/hooks/useLocale"; import { isBrandingHidden } from "@lib/isBrandingHidden"; import prisma from "@lib/prisma"; import { trpc } from "@lib/trpc"; import { inferSSRProps } from "@lib/types/inferSSRProps"; import ImageUploader from "@components/ImageUploader"; import Modal from "@components/Modal"; import SettingsShell from "@components/Settings"; import Shell from "@components/Shell"; import { Alert } from "@components/ui/Alert"; import Avatar from "@components/ui/Avatar"; import Badge from "@components/ui/Badge"; import Button from "@components/ui/Button"; import { UsernameInput } from "@components/ui/UsernameInput"; const themeOptions = [ { value: "light", label: "Light" }, { value: "dark", label: "Dark" }, ]; type Props = inferSSRProps; function HideBrandingInput(props: { // hideBrandingRef: RefObject; user: Props["user"]; }) { const [modelOpen, setModalOpen] = useState(false); return ( <> { if (!e.currentTarget.checked || props.user.plan !== "FREE") { return; } // prevent checking the input e.preventDefault(); setModalOpen(true); }} />

In order to remove the Cal branding from your booking pages, you need to upgrade to a paid account.

{" "} To upgrade go to{" "} cal.com/upgrade .

} open={modelOpen} handleClose={() => setModalOpen(false)} /> ); } export default function Settings(props: Props) { const { locale } = useLocale({ localeProp: props.localeProp }); const mutation = trpc.useMutation("viewer.updateProfile"); const [successModalOpen, setSuccessModalOpen] = useState(false); const usernameRef = useRef(null); const nameRef = useRef(null); const descriptionRef = useRef(); const avatarRef = useRef(null); const hideBrandingRef = useRef(null); const [selectedTheme, setSelectedTheme] = useState({ value: props.user.theme }); const [selectedTimeZone, setSelectedTimeZone] = useState({ value: props.user.timeZone }); const [selectedWeekStartDay, setSelectedWeekStartDay] = useState({ value: props.user.weekStart }); const [selectedLanguage, setSelectedLanguage] = useState({ value: locale, label: props.localeLabels[locale], }); const [imageSrc, setImageSrc] = useState(props.user.avatar); const [hasErrors, setHasErrors] = useState(false); const [errorMessage, setErrorMessage] = useState(""); useEffect(() => { setSelectedTheme( props.user.theme ? themeOptions.find((theme) => theme.value === props.user.theme) : null ); setSelectedWeekStartDay({ value: props.user.weekStart, label: props.user.weekStart }); setSelectedLanguage({ value: locale, label: props.localeLabels[locale] }); }, []); const closeSuccessModal = () => { setSuccessModalOpen(false); }; const handleAvatarChange = (newAvatar) => { avatarRef.current.value = newAvatar; const nativeInputValueSetter = Object.getOwnPropertyDescriptor( window.HTMLInputElement.prototype, "value" ).set; nativeInputValueSetter.call(avatarRef.current, newAvatar); const ev2 = new Event("input", { bubbles: true }); avatarRef.current.dispatchEvent(ev2); updateProfileHandler(ev2); setImageSrc(newAvatar); }; async function updateProfileHandler(event) { event.preventDefault(); const enteredUsername = usernameRef.current.value.toLowerCase(); const enteredName = nameRef.current.value; const enteredDescription = descriptionRef.current.value; const enteredAvatar = avatarRef.current.value; const enteredTimeZone = selectedTimeZone.value; const enteredWeekStartDay = selectedWeekStartDay.value; const enteredHideBranding = hideBrandingRef.current.checked; const enteredLanguage = selectedLanguage.value; // TODO: Add validation await mutation .mutateAsync({ username: enteredUsername, name: enteredName, bio: enteredDescription, avatar: enteredAvatar, timeZone: enteredTimeZone, weekStart: asStringOrUndefined(enteredWeekStartDay), hideBranding: enteredHideBranding, theme: asStringOrUndefined(selectedTheme?.value), locale: enteredLanguage, }) .then(() => { setSuccessModalOpen(true); setHasErrors(false); // dismiss any open errors }) .catch((err) => { setHasErrors(true); setErrorMessage(err.message); document?.getElementsByTagName("main")[0]?.scrollTo({ top: 0, behavior: "smooth" }); }); } return (
{hasErrors && }

setSelectedTheme(e.target.checked ? null : themeOptions[0])} defaultChecked={!selectedTheme} className="focus:ring-neutral-500 h-4 w-4 text-neutral-900 border-gray-300 rounded-sm" />

Hide all Cal.com branding from your public pages.

{/*
} />
*/}
); } export const getServerSideProps = async (context: GetServerSidePropsContext) => { const session = await getSession(context); const locale = await extractLocaleInfo(context.req); if (!session?.user?.id) { return { redirect: { permanent: false, destination: "/auth/login" } }; } const user = await prisma.user.findUnique({ where: { id: session.user.id, }, select: { id: true, username: true, name: true, email: true, bio: true, avatar: true, timeZone: true, weekStart: true, hideBranding: true, theme: true, plan: true, }, }); if (!user) { throw new Error("User seems logged in but cannot be found in the db"); } return { props: { session, localeProp: locale, localeOptions, localeLabels, user: { ...user, emailMd5: crypto.createHash("md5").update(user.email).digest("hex"), }, ...(await serverSideTranslations(locale, ["common"])), }, }; };