mirror of https://github.com/coder/coder.git
103 lines
2.7 KiB
TypeScript
103 lines
2.7 KiB
TypeScript
import type { Interpolation, Theme } from "@emotion/react";
|
|
import type { FC } from "react";
|
|
import { useLocation } from "react-router-dom";
|
|
import type { AuthMethods } from "api/typesGenerated";
|
|
import { CoderIcon } from "components/Icons/CoderIcon";
|
|
import { Loader } from "components/Loader/Loader";
|
|
import { getApplicationName, getLogoURL } from "utils/appearance";
|
|
import { retrieveRedirect } from "utils/redirect";
|
|
import { SignInForm } from "./SignInForm";
|
|
|
|
export interface LoginPageViewProps {
|
|
authMethods: AuthMethods | undefined;
|
|
error: unknown;
|
|
isLoading: boolean;
|
|
isSigningIn: boolean;
|
|
onSignIn: (credentials: { email: string; password: string }) => void;
|
|
}
|
|
|
|
export const LoginPageView: FC<LoginPageViewProps> = ({
|
|
authMethods,
|
|
error,
|
|
isLoading,
|
|
isSigningIn,
|
|
onSignIn,
|
|
}) => {
|
|
const location = useLocation();
|
|
const redirectTo = retrieveRedirect(location.search);
|
|
// This allows messages to be displayed at the top of the sign in form.
|
|
// Helpful for any redirects that want to inform the user of something.
|
|
const message = new URLSearchParams(location.search).get("message");
|
|
const applicationName = getApplicationName();
|
|
const logoURL = getLogoURL();
|
|
const applicationLogo = logoURL ? (
|
|
<img
|
|
alt={applicationName}
|
|
src={logoURL}
|
|
// This prevent browser to display the ugly error icon if the
|
|
// image path is wrong or user didn't finish typing the url
|
|
onError={(e) => (e.currentTarget.style.display = "none")}
|
|
onLoad={(e) => (e.currentTarget.style.display = "inline")}
|
|
css={{
|
|
maxWidth: "200px",
|
|
}}
|
|
className="application-logo"
|
|
/>
|
|
) : (
|
|
<CoderIcon fill="white" opacity={1} css={styles.icon} />
|
|
);
|
|
|
|
return (
|
|
<div css={styles.root}>
|
|
<div css={styles.container}>
|
|
{applicationLogo}
|
|
{isLoading ? (
|
|
<Loader />
|
|
) : (
|
|
<SignInForm
|
|
authMethods={authMethods}
|
|
redirectTo={redirectTo}
|
|
isSigningIn={isSigningIn}
|
|
error={error}
|
|
message={message}
|
|
onSubmit={onSignIn}
|
|
/>
|
|
)}
|
|
<footer css={styles.footer}>
|
|
Copyright © {new Date().getFullYear()} Coder Technologies, Inc.
|
|
</footer>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const styles = {
|
|
root: {
|
|
padding: 24,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
minHeight: "100%",
|
|
textAlign: "center",
|
|
},
|
|
|
|
container: {
|
|
width: "100%",
|
|
maxWidth: 320,
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
gap: 16,
|
|
},
|
|
|
|
icon: {
|
|
fontSize: 64,
|
|
},
|
|
|
|
footer: (theme) => ({
|
|
fontSize: 12,
|
|
color: theme.palette.text.secondary,
|
|
marginTop: 24,
|
|
}),
|
|
} satisfies Record<string, Interpolation<Theme>>;
|