fix: improve UX of team invite by copy link (#11009)
This commit is contained in:
parent
13f9e97015
commit
0150041496
|
@ -52,6 +52,8 @@ export default function Login({
|
||||||
totpEmail,
|
totpEmail,
|
||||||
}: inferSSRProps<typeof _getServerSideProps> & WithNonceProps) {
|
}: inferSSRProps<typeof _getServerSideProps> & WithNonceProps) {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
const isTeamInvite = searchParams.get("teamInvite");
|
||||||
|
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const formSchema = z
|
const formSchema = z
|
||||||
|
@ -95,7 +97,9 @@ export default function Login({
|
||||||
callbackUrl = safeCallbackUrl || "";
|
callbackUrl = safeCallbackUrl || "";
|
||||||
|
|
||||||
const LoginFooter = (
|
const LoginFooter = (
|
||||||
<a href={`${WEBSITE_URL}/signup`} className="text-brand-500 font-medium">
|
<a
|
||||||
|
href={callbackUrl !== "" ? `${WEBSITE_URL}/signup?callbackUrl=${callbackUrl}` : `${WEBSITE_URL}/signup`}
|
||||||
|
className="text-brand-500 font-medium">
|
||||||
{t("dont_have_an_account")}
|
{t("dont_have_an_account")}
|
||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
|
@ -184,6 +188,9 @@ export default function Login({
|
||||||
? LoginFooter
|
? LoginFooter
|
||||||
: null
|
: null
|
||||||
}>
|
}>
|
||||||
|
{isTeamInvite && (
|
||||||
|
<Alert severity="info" message={t("signin_or_signup_to_accept_invite")} className="mb-4 mt-4" />
|
||||||
|
)}
|
||||||
<FormProvider {...methods}>
|
<FormProvider {...methods}>
|
||||||
<form onSubmit={methods.handleSubmit(onSubmit)} noValidate data-testid="login-form">
|
<form onSubmit={methods.handleSubmit(onSubmit)} noValidate data-testid="login-form">
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||||
import { useFlagMap } from "@calcom/features/flags/context/provider";
|
import { useFlagMap } from "@calcom/features/flags/context/provider";
|
||||||
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
|
||||||
import { IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
|
import { IS_SELF_HOSTED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import slugify from "@calcom/lib/slugify";
|
import slugify from "@calcom/lib/slugify";
|
||||||
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
|
||||||
|
@ -34,6 +35,23 @@ type FormValues = z.infer<typeof signupSchema>;
|
||||||
|
|
||||||
type SignupProps = inferSSRProps<typeof getServerSideProps>;
|
type SignupProps = inferSSRProps<typeof getServerSideProps>;
|
||||||
|
|
||||||
|
const getSafeCallbackUrl = (url: string | null) => {
|
||||||
|
if (!url) return null;
|
||||||
|
|
||||||
|
let callbackUrl = url;
|
||||||
|
|
||||||
|
if (/"\//.test(callbackUrl)) callbackUrl = callbackUrl.substring(1);
|
||||||
|
|
||||||
|
// If not absolute URL, make it absolute
|
||||||
|
if (!/^https?:\/\//.test(callbackUrl)) {
|
||||||
|
callbackUrl = `${WEBAPP_URL}/${callbackUrl}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const safeCallbackUrl = getSafeRedirectUrl(callbackUrl);
|
||||||
|
|
||||||
|
return safeCallbackUrl;
|
||||||
|
};
|
||||||
|
|
||||||
export default function Signup({ prepopulateFormValues, token, orgSlug }: SignupProps) {
|
export default function Signup({ prepopulateFormValues, token, orgSlug }: SignupProps) {
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
|
@ -55,6 +73,7 @@ export default function Signup({ prepopulateFormValues, token, orgSlug }: Signup
|
||||||
throw new Error(err.message);
|
throw new Error(err.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const callbackUrl = getSafeCallbackUrl(searchParams.get("callbackUrl"));
|
||||||
|
|
||||||
const signUp: SubmitHandler<FormValues> = async (data) => {
|
const signUp: SubmitHandler<FormValues> = async (data) => {
|
||||||
await fetch("/api/auth/signup", {
|
await fetch("/api/auth/signup", {
|
||||||
|
@ -72,13 +91,10 @@ export default function Signup({ prepopulateFormValues, token, orgSlug }: Signup
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
telemetry.event(telemetryEventTypes.signup, collectPageParameters());
|
telemetry.event(telemetryEventTypes.signup, collectPageParameters());
|
||||||
const verifyOrGettingStarted = flags["email-verification"] ? "auth/verify-email" : "getting-started";
|
const verifyOrGettingStarted = flags["email-verification"] ? "auth/verify-email" : "getting-started";
|
||||||
|
|
||||||
await signIn<"credentials">("credentials", {
|
await signIn<"credentials">("credentials", {
|
||||||
...data,
|
...data,
|
||||||
callbackUrl: `${
|
callbackUrl: `${callbackUrl ? callbackUrl : `${WEBAPP_URL}/${verifyOrGettingStarted}`}?from=signup`,
|
||||||
searchParams?.get("callbackUrl")
|
|
||||||
? `${WEBAPP_URL}/${searchParams.get("callbackUrl")}`
|
|
||||||
: `${WEBAPP_URL}/${verifyOrGettingStarted}`
|
|
||||||
}?from=signup`,
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
@ -157,9 +173,7 @@ export default function Signup({ prepopulateFormValues, token, orgSlug }: Signup
|
||||||
className="w-full justify-center"
|
className="w-full justify-center"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
signIn("Cal.com", {
|
signIn("Cal.com", {
|
||||||
callbackUrl: searchParams?.get("callbackUrl")
|
callbackUrl: callbackUrl ? callbackUrl : `${WEBAPP_URL}/getting-started`,
|
||||||
? `${WEBAPP_URL}/${searchParams.get("callbackUrl")}`
|
|
||||||
: `${WEBAPP_URL}/getting-started`,
|
|
||||||
})
|
})
|
||||||
}>
|
}>
|
||||||
{t("login_instead")}
|
{t("login_instead")}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import type { GetServerSidePropsContext } from "next";
|
import type { GetServerSidePropsContext } from "next";
|
||||||
|
|
||||||
import { getLayout } from "@calcom/features/MainLayout";
|
import { getLayout } from "@calcom/features/MainLayout";
|
||||||
|
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||||
import { TeamsListing } from "@calcom/features/ee/teams/components";
|
import { TeamsListing } from "@calcom/features/ee/teams/components";
|
||||||
import { ShellMain } from "@calcom/features/shell/Shell";
|
import { ShellMain } from "@calcom/features/shell/Shell";
|
||||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
|
||||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
import { trpc } from "@calcom/trpc/react";
|
||||||
import { Button } from "@calcom/ui";
|
import { Button } from "@calcom/ui";
|
||||||
|
@ -41,6 +43,21 @@ function Teams() {
|
||||||
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
|
||||||
const ssr = await ssrInit(context);
|
const ssr = await ssrInit(context);
|
||||||
await ssr.viewer.me.prefetch();
|
await ssr.viewer.me.prefetch();
|
||||||
|
const session = await getServerSession({ req: context.req, res: context.res });
|
||||||
|
const token = context.query?.token;
|
||||||
|
const resolvedUrl = context.resolvedUrl;
|
||||||
|
|
||||||
|
const callbackUrl = token ? getSafeRedirectUrl(`${WEBAPP_URL}${resolvedUrl}`) : null;
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return {
|
||||||
|
redirect: {
|
||||||
|
destination: callbackUrl ? `/auth/login?callbackUrl=${callbackUrl}&teamInvite=true` : "/auth/login",
|
||||||
|
permanent: false,
|
||||||
|
},
|
||||||
|
props: {},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return { props: { trpcState: ssr.dehydrate() } };
|
return { props: { trpcState: ssr.dehydrate() } };
|
||||||
};
|
};
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
"invite_team_individual_segment": "Invite individual",
|
"invite_team_individual_segment": "Invite individual",
|
||||||
"invite_team_bulk_segment": "Bulk import",
|
"invite_team_bulk_segment": "Bulk import",
|
||||||
"invite_team_notifcation_badge": "Inv.",
|
"invite_team_notifcation_badge": "Inv.",
|
||||||
|
"signin_or_signup_to_accept_invite": "You need to Sign in or Sign up to see team invitation.",
|
||||||
"your_event_has_been_scheduled": "Your event has been scheduled",
|
"your_event_has_been_scheduled": "Your event has been scheduled",
|
||||||
"your_event_has_been_scheduled_recurring": "Your recurring event has been scheduled",
|
"your_event_has_been_scheduled_recurring": "Your recurring event has been scheduled",
|
||||||
"accept_our_license": "Accept our license by changing the .env variable <1>NEXT_PUBLIC_LICENSE_CONSENT</1> to '{{agree}}'.",
|
"accept_our_license": "Accept our license by changing the .env variable <1>NEXT_PUBLIC_LICENSE_CONSENT</1> to '{{agree}}'.",
|
||||||
|
|
Loading…
Reference in New Issue
Block a user