sendou.ink/app/components/layout/AuthErrorDialog.tsx
2026-08-03 09:38:09 +03:00

66 lines
1.8 KiB
TypeScript

import type { TFunction } from "i18next";
import { createPortal } from "react-dom";
import { useTranslation } from "react-i18next";
import { SendouDialog } from "~/components/elements/Dialog";
import { useUser } from "~/features/auth/core/user";
import { useHydrated } from "~/hooks/useHydrated";
import { useSearchParam } from "~/modules/search-params/hooks";
import { SENDOU_INK_DISCORD_URL } from "~/utils/urls";
import { authErrorSearchParams } from "./layout-search-params";
import styles from "./UserItem.module.css";
export function AuthErrorDialog() {
const { t } = useTranslation();
const isHydrated = useHydrated();
const user = useUser();
const [authError] = useSearchParam(authErrorSearchParams, "authError");
if (authError == null || !isHydrated || user) return null;
return createPortal(
<SendouDialog
isDismissable
onCloseTo="/"
heading={
authError === "aborted"
? t("auth.errors.aborted")
: t("auth.errors.failed")
}
>
<div className={`stack md ${styles.userItem}`}>
{authErrorContent(authError, t)}
</div>
</SendouDialog>,
document.body,
);
}
function authErrorContent(authError: string, t: TFunction) {
switch (authError) {
case "aborted":
return t("auth.errors.discordPermissions");
case "discordOverloaded":
return (
<>
{t("auth.errors.discordOverloaded")}{" "}
<a href={SENDOU_INK_DISCORD_URL} target="_blank" rel="noreferrer">
{SENDOU_INK_DISCORD_URL}
</a>
</>
);
case "unverifiedEmail":
return t("auth.errors.unverifiedEmail");
case "browserPrivacy":
return t("auth.errors.browserPrivacy");
default:
return (
<>
{t("auth.errors.unknown")}{" "}
<a href={SENDOU_INK_DISCORD_URL} target="_blank" rel="noreferrer">
{SENDOU_INK_DISCORD_URL}
</a>
</>
);
}
}