Add premium username tag

pull/11421/merge^2
Sean Brydon 2023-09-15 14:15:21 +01:00
parent 260f0aaa20
commit bc6af6ea3d
2 changed files with 35 additions and 15 deletions

View File

@ -1,5 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { ShieldCheckIcon } from "lucide-react"; import { Info, Loader2, ShieldCheckIcon, StarIcon } from "lucide-react";
import type { GetServerSidePropsContext } from "next"; import type { GetServerSidePropsContext } from "next";
import { signIn } from "next-auth/react"; import { signIn } from "next-auth/react";
import Link from "next/link"; import Link from "next/link";
@ -12,6 +12,7 @@ import { Trans } from "react-i18next";
import { z } from "zod"; import { z } from "zod";
import getStripe from "@calcom/app-store/stripepayment/lib/client"; import getStripe from "@calcom/app-store/stripepayment/lib/client";
import { getPremiumPlanPriceValue } from "@calcom/app-store/stripepayment/lib/utils";
import { getOrgFullDomain } from "@calcom/ee/organizations/lib/orgDomains"; import { getOrgFullDomain } from "@calcom/ee/organizations/lib/orgDomains";
import { checkPremiumUsername } from "@calcom/features/ee/common/lib/checkPremiumUsername"; import { checkPremiumUsername } from "@calcom/features/ee/common/lib/checkPremiumUsername";
import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml"; import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
@ -42,12 +43,15 @@ type FormValues = z.infer<typeof signupSchema>;
type SignupProps = inferSSRProps<typeof getServerSideProps>; type SignupProps = inferSSRProps<typeof getServerSideProps>;
function UsernameField({ ...props }: React.ComponentProps<typeof TextField>) { function UsernameField({
...props
}: React.ComponentProps<typeof TextField> & { setPremiumExternal?: () => void }) {
const { t } = useLocale(); const { t } = useLocale();
const { formState, watch, setError, register } = useFormContext<FormValues>(); const { formState, watch, setError, register } = useFormContext<FormValues>();
const { errors } = formState; const { errors } = formState;
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [premium, setPremium] = useState(false); const [premium, setPremium] = useState(false);
const [taken, setTaken] = useState(false);
const watchedUsername = watch("username"); const watchedUsername = watch("username");
const debouncedUsername = useDebounce(watchedUsername, 500); const debouncedUsername = useDebounce(watchedUsername, 500);
@ -55,23 +59,20 @@ function UsernameField({ ...props }: React.ComponentProps<typeof TextField>) {
async function checkUsername() { async function checkUsername() {
if (!debouncedUsername) { if (!debouncedUsername) {
setLoading(false); setLoading(false);
setPremium(false);
setTaken(false);
return; return;
} }
setLoading(true); setLoading(true);
fetchUsername(debouncedUsername) fetchUsername(debouncedUsername)
.then(({ data }) => { .then(({ data }) => {
if (data.premium) { if (data.premium) {
// setError("username", {
// type: "manual",
// message: t("premium_username_error"),
// });
setPremium(true); setPremium(true);
} else {
setPremium(false);
} }
if (!data.available) { if (!data.available) {
setError("username", { setTaken(true);
type: "manual",
message: t("already_in_use_error"),
});
} }
}) })
.finally(() => { .finally(() => {
@ -82,13 +83,31 @@ function UsernameField({ ...props }: React.ComponentProps<typeof TextField>) {
}, [debouncedUsername, t, setError]); }, [debouncedUsername, t, setError]);
return ( return (
<> <div>
<TextField {...props} {...register("username")} hintErrors={["premium"]} /> <TextField {...props} {...register("username")} />
<div className="text-gray text-default flex items-center text-sm"> <div className="text-gray text-default flex items-center text-sm">
{loading && <span className="text-default mr-2 h-4 w-4 animate-spin"></span>} <p className="flex items-center text-sm ">
{errors.username?.message} {loading ? (
<>
<Loader2 className="mr-1 inline-block h-4 w-4 animate-spin" />
{t("loading")}
</>
) : taken ? (
<div className="text-error">
<Info className="mr-1 inline-block h-4 w-4" />
{t("already_taken")}
</div>
) : premium ? (
<>
<StarIcon className="mr-1 inline-block h-4 w-4" />
{t("premium_username", {
price: getPremiumPlanPriceValue(),
})}
</>
) : null}
</p>
</div> </div>
</> </div>
); );
} }

View File

@ -1138,6 +1138,7 @@
"active_on": "Active on", "active_on": "Active on",
"workflow_updated_successfully": "{{workflowName}} workflow updated successfully", "workflow_updated_successfully": "{{workflowName}} workflow updated successfully",
"premium_to_standard_username_description": "This is a standard username and updating will take you to billing to downgrade.", "premium_to_standard_username_description": "This is a standard username and updating will take you to billing to downgrade.",
"premium_username": "This is a premium username, get yours for {{price}}",
"current": "Current", "current": "Current",
"premium": "premium", "premium": "premium",
"standard": "standard", "standard": "standard",