fix(@cal.com/web): update debounce logic to work correctly and not show non-premium usernames as premium (#15629)
* fix(@cal.com/web): update debounce logic to work correctly and not show non-premium usernames as premium - removes redundant useMemo hook from UsernameTextfield.tsx & PremiumTextField.tsx - cancles the debounceAPICall on every unmount of UsernameTextfield.tsx & PremiumTextfield.tsx via useEffect cleanup function Fixes #15628 * fix(@cal.com/web): update the debounce logic to use the pre-existing useDebounce hook - update the debounce logic in UsernameTextField.tsx & PremiumTextField.tsx to use the pre-existing useDebounce hook instead of loadsh debounce - update the debounce delay to 600ms to be consistent with the signup.tsx behavior Fixes #15628 * fix: signup debounce not working properly --------- Co-authored-by: Amit91848 <samit91848@gmail.com>
This commit is contained in:
co-authored by
Amit91848
parent
726c938b6d
commit
e9d828639a
@@ -1,15 +1,16 @@
|
||||
import classNames from "classnames";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { debounce, noop } from "lodash";
|
||||
import { noop } from "lodash";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import type { RefCallback } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { getPremiumPlanPriceValue } from "@calcom/app-store/stripepayment/lib/utils";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { fetchUsername } from "@calcom/lib/fetchUsername";
|
||||
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
|
||||
import { useDebounce } from "@calcom/lib/hooks/useDebounce";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { TRPCClientErrorLike } from "@calcom/trpc/client";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
@@ -71,17 +72,8 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
||||
const isCurrentUsernamePremium =
|
||||
user && user.metadata && hasKeyInMetadata(user, "isPremium") ? !!user.metadata.isPremium : false;
|
||||
const [isInputUsernamePremium, setIsInputUsernamePremium] = useState(false);
|
||||
const debouncedApiCall = useMemo(
|
||||
() =>
|
||||
debounce(async (username: string) => {
|
||||
// TODO: Support orgSlug
|
||||
const { data } = await fetchUsername(username, null);
|
||||
setMarkAsError(!data.available && !!currentUsername && username !== currentUsername);
|
||||
setIsInputUsernamePremium(data.premium);
|
||||
setUsernameIsAvailable(data.available);
|
||||
}, 150),
|
||||
[currentUsername]
|
||||
);
|
||||
// debounce the username input, set the delay to 600ms to be consistent with signup form
|
||||
const debouncedUsername = useDebounce(inputUsernameValue, 600);
|
||||
|
||||
useEffect(() => {
|
||||
// Use the current username or if it's not set, use the one available from stripe
|
||||
@@ -89,12 +81,22 @@ const PremiumTextfield = (props: ICustomUsernameProps) => {
|
||||
}, [setInputUsernameValue, currentUsername, stripeCustomer?.username]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!inputUsernameValue) {
|
||||
debouncedApiCall.cancel();
|
||||
return;
|
||||
async function checkUsername(username: string | undefined) {
|
||||
if (!username) {
|
||||
setUsernameIsAvailable(false);
|
||||
setMarkAsError(false);
|
||||
setIsInputUsernamePremium(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const { data } = await fetchUsername(username, null);
|
||||
setMarkAsError(!data.available && !!currentUsername && username !== currentUsername);
|
||||
setIsInputUsernamePremium(data.premium);
|
||||
setUsernameIsAvailable(data.available);
|
||||
}
|
||||
debouncedApiCall(inputUsernameValue);
|
||||
}, [debouncedApiCall, inputUsernameValue]);
|
||||
|
||||
checkUsername(debouncedUsername);
|
||||
}, [debouncedUsername, currentUsername]);
|
||||
|
||||
const updateUsername = trpc.viewer.updateProfile.useMutation({
|
||||
onSuccess: async () => {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import classNames from "classnames";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { debounce, noop } from "lodash";
|
||||
import { noop } from "lodash";
|
||||
import { useSession } from "next-auth/react";
|
||||
import type { RefCallback } from "react";
|
||||
import { useEffect, useMemo, useState } 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";
|
||||
@@ -41,31 +42,28 @@ const UsernameTextfield = (props: ICustomUsernameProps & Partial<React.Component
|
||||
const [markAsError, setMarkAsError] = useState(false);
|
||||
const [openDialogSaveUsername, setOpenDialogSaveUsername] = useState(false);
|
||||
|
||||
const debouncedApiCall = useMemo(
|
||||
() =>
|
||||
debounce(async (username) => {
|
||||
// TODO: Support orgSlug
|
||||
// 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);
|
||||
}, 150),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!inputUsernameValue) {
|
||||
debouncedApiCall.cancel();
|
||||
setUsernameIsAvailable(false);
|
||||
setMarkAsError(false);
|
||||
return;
|
||||
} else {
|
||||
setUsernameIsAvailable(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentUsername !== inputUsernameValue) {
|
||||
debouncedApiCall(inputUsernameValue);
|
||||
} else {
|
||||
setUsernameIsAvailable(false);
|
||||
}
|
||||
}, [inputUsernameValue, debouncedApiCall, currentUsername]);
|
||||
checkUsername(debouncedUsername);
|
||||
}, [debouncedUsername, currentUsername]);
|
||||
|
||||
const updateUsernameMutation = trpc.viewer.updateProfile.useMutation({
|
||||
onSuccess: async () => {
|
||||
|
||||
@@ -123,15 +123,8 @@ function UsernameField({
|
||||
});
|
||||
}
|
||||
checkUsername();
|
||||
}, [
|
||||
debouncedUsername,
|
||||
setPremium,
|
||||
disabled,
|
||||
orgSlug,
|
||||
setUsernameTaken,
|
||||
formState.isSubmitting,
|
||||
formState.isSubmitSuccessful,
|
||||
]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [debouncedUsername, disabled, orgSlug, formState.isSubmitting, formState.isSubmitSuccessful]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user