import classNames from "classnames"; // eslint-disable-next-line no-restricted-imports import { noop } from "lodash"; import { useSession } from "next-auth/react"; import type { RefCallback } from "react"; import { useEffect, useState } from "react"; import { fetchUsername } from "@calcom/lib/fetchUsername"; import { useDebounce } from "@calcom/lib/hooks/useDebounce"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import type { TRPCClientErrorLike } from "@calcom/trpc/client"; import { trpc } from "@calcom/trpc/react"; import type { AppRouter } from "@calcom/trpc/server/routers/_app"; import { Button, Dialog, DialogClose, DialogContent, TextField, DialogFooter, Tooltip } from "@calcom/ui"; import { Icon } from "@calcom/ui"; interface ICustomUsernameProps { currentUsername: string | undefined; setCurrentUsername?: (newUsername: string) => void; inputUsernameValue: string | undefined; usernameRef: RefCallback; setInputUsernameValue: (value: string) => void; onSuccessMutation?: () => void; onErrorMutation?: (error: TRPCClientErrorLike) => void; } const UsernameTextfield = (props: ICustomUsernameProps & Partial>) => { const { t } = useLocale(); const { update } = useSession(); const { currentUsername, setCurrentUsername = noop, inputUsernameValue, setInputUsernameValue, usernameRef, onSuccessMutation, onErrorMutation, ...rest } = props; const [usernameIsAvailable, setUsernameIsAvailable] = useState(false); const [markAsError, setMarkAsError] = useState(false); const [openDialogSaveUsername, setOpenDialogSaveUsername] = useState(false); // debounce the username input, set the delay to 600ms to be consistent with signup form const debouncedUsername = useDebounce(inputUsernameValue, 600); useEffect(() => { async function checkUsername(username: string | undefined) { if (!username) { setUsernameIsAvailable(false); setMarkAsError(false); return; } if (currentUsername !== username) { const { data } = await fetchUsername(username, null); setMarkAsError(!data.available); setUsernameIsAvailable(data.available); } else { setUsernameIsAvailable(false); } } checkUsername(debouncedUsername); }, [debouncedUsername, currentUsername]); const updateUsernameMutation = trpc.viewer.updateProfile.useMutation({ onSuccess: async () => { onSuccessMutation && (await onSuccessMutation()); setOpenDialogSaveUsername(false); setCurrentUsername(inputUsernameValue); await update({ username: inputUsernameValue }); }, onError: (error) => { onErrorMutation && onErrorMutation(error); }, }); const ActionButtons = () => { return usernameIsAvailable && currentUsername !== inputUsernameValue ? (
) : ( <> ); }; const updateUsername = async () => { updateUsernameMutation.mutate({ username: inputUsernameValue, }); }; return (
{ event.preventDefault(); setInputUsernameValue(event.target.value); }} data-testid="username-input" {...rest} /> {currentUsername !== inputUsernameValue && (
{usernameIsAvailable ? ( ) : ( <> )}
)}
{markAsError &&

{t("username_already_taken")}

} {usernameIsAvailable && currentUsername !== inputUsernameValue && (
)}

{t("current_username")}

{currentUsername}

{t("new_username")}

{inputUsernameValue}

setOpenDialogSaveUsername(false)}> {t("cancel")}
); }; export { UsernameTextfield };