feat: tracking and displaying last used login method (#16356)

This commit is contained in:
Anik Dhabal Babu
2024-08-26 12:13:42 +00:00
committed by GitHub
parent 6529b49c3c
commit 2fb4289798
4 changed files with 53 additions and 7 deletions
+16 -5
View File
@@ -14,6 +14,7 @@ import { ErrorCode } from "@calcom/features/auth/lib/ErrorCode";
import { HOSTED_CAL_FEATURES, WEBAPP_URL, WEBSITE_URL } from "@calcom/lib/constants";
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
import { useLastUsed, LastUsed } from "@calcom/lib/hooks/useLastUsed";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@calcom/lib/telemetry";
import { trpc } from "@calcom/trpc/react";
@@ -68,6 +69,7 @@ inferSSRProps<typeof getServerSideProps> & WithNonceProps<{}>) {
const [twoFactorRequired, setTwoFactorRequired] = useState(!!totpEmail || false);
const [twoFactorLostAccess, setTwoFactorLostAccess] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [lastUsed, setLastUsed] = useLastUsed();
const errorMessages: { [key: string]: string } = {
// [ErrorCode.SecondFactorRequired]: t("2fa_enabled_instructions"),
@@ -151,8 +153,10 @@ inferSSRProps<typeof getServerSideProps> & WithNonceProps<{}>) {
});
if (!res) setErrorMessage(errorMessages[ErrorCode.InternalServerError]);
// we're logged in! let's do a hard refresh to the desired url
else if (!res.error) router.push(callbackUrl);
else if (res.error === ErrorCode.SecondFactorRequired) setTwoFactorRequired(true);
else if (!res.error) {
setLastUsed("credentials");
router.push(callbackUrl);
} else if (res.error === ErrorCode.SecondFactorRequired) setTwoFactorRequired(true);
else if (res.error === ErrorCode.IncorrectBackupCode) setErrorMessage(t("incorrect_backup_code"));
else if (res.error === ErrorCode.MissingBackupCodes) setErrorMessage(t("missing_backup_codes"));
// fallback if error not found
@@ -232,7 +236,10 @@ inferSSRProps<typeof getServerSideProps> & WithNonceProps<{}>) {
color="primary"
disabled={formState.isSubmitting}
className="w-full justify-center">
{twoFactorRequired ? t("submit") : t("sign_in")}
<span>{twoFactorRequired ? t("submit") : t("sign_in")}</span>
{lastUsed === "credentials" && (
<span className="absolute right-3 text-xs text-gray-600">{t("last_used")}</span>
)}
</Button>
</div>
</form>
@@ -249,11 +256,15 @@ inferSSRProps<typeof getServerSideProps> & WithNonceProps<{}>) {
CustomStartIcon={<GoogleIcon />}
onClick={async (e) => {
e.preventDefault();
await signIn("google", {
const res = await signIn("google", {
callbackUrl,
});
if (res && !res.error) {
setLastUsed("google");
}
}}>
{t("signin_with_google")}
<span>{t("signin_with_google")}</span>
{lastUsed === "google" && <LastUsed />}
</Button>
)}
{displaySSOLogin && (
@@ -957,6 +957,7 @@
"signin_with_google": "Sign in with Google",
"signin_with_saml": "Sign in with SAML",
"signin_with_saml_oidc": "Sign in with SAML/OIDC",
"last_used": "Last used",
"you_will_need_to_generate": "You will need to generate an access token from your old scheduling tool.",
"import": "Import",
"import_from": "Import from",
+8 -2
View File
@@ -4,6 +4,7 @@ import { useFormContext } from "react-hook-form";
import z from "zod";
import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
import { useLastUsed, LastUsed } from "@calcom/lib/hooks/useLastUsed";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Button } from "@calcom/ui";
@@ -21,10 +22,14 @@ const schema = z.object({
export function SAMLLogin({ samlTenantID, samlProductID, setErrorMessage }: Props) {
const { t } = useLocale();
const methods = useFormContext();
const [lastUsed, setLastUsed] = useLastUsed();
const mutation = trpc.viewer.public.samlTenantProduct.useMutation({
onSuccess: async (data) => {
await signIn("saml", {}, { tenant: data.tenant, product: data.product });
const res = await signIn("saml", {}, { tenant: data.tenant, product: data.product });
if (res && !res.error) {
setLastUsed("saml");
}
},
onError: (err) => {
setErrorMessage(t(err.message));
@@ -62,7 +67,8 @@ export function SAMLLogin({ samlTenantID, samlProductID, setErrorMessage }: Prop
email,
});
}}>
{t("signin_with_saml_oidc")}
<span>{t("signin_with_saml_oidc")}</span>
{lastUsed === "saml" && <LastUsed />}
</Button>
);
}
+28
View File
@@ -0,0 +1,28 @@
import { useState, useEffect } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { localStorage } from "@calcom/lib/webstorage";
type LoginType = "saml" | "google" | "credentials" | undefined;
export function useLastUsed() {
const [lastUsed, setLastUsed] = useState<LoginType>(() => {
const storedValue = localStorage.getItem("last_cal_login");
return storedValue ? (storedValue as LoginType) : undefined;
});
useEffect(() => {
if (lastUsed) {
localStorage.setItem("last_cal_login", lastUsed);
} else {
localStorage.removeItem("last_cal_login");
}
}, [lastUsed]);
return [lastUsed, setLastUsed] as const;
}
export const LastUsed = () => {
const { t } = useLocale();
return <span className="text-subtle absolute right-3 text-xs">{t("last_used")}</span>;
};