pankod/refine

View on GitHub
packages/mantine/src/components/pages/auth/components/login/index.tsx

Summary

Maintainability
A
3 hrs
Test Coverage
import React from "react";
import {
  LoginPageProps,
  LoginFormTypes,
  useRouterType,
  useLink,
  useActiveAuthProvider,
} from "@refinedev/core";
import { useLogin, useTranslate, useRouterContext } from "@refinedev/core";
import {
  Box,
  Card,
  Checkbox,
  PasswordInput,
  Space,
  TextInput,
  Title,
  Anchor,
  Button,
  Text,
  Divider,
  Stack,
  BoxProps,
  CardProps,
  useMantineTheme,
} from "@mantine/core";

import { ThemedTitleV2 } from "@components";
import { FormContext } from "@contexts/form-context";
import {
  layoutStyles,
  cardStyles,
  titleStyles,
  pageTitleStyles,
} from "../styles";
import { FormPropsType } from "../..";

type LoginProps = LoginPageProps<BoxProps, CardProps, FormPropsType>;

/**
 * **refine** has a default login page form which is served on `/login` route when the `authProvider` configuration is provided.
 * @see {@link https://refine.dev/docs/api-reference/mantine/components/mantine-auth-page/#login} for more details.
 */
export const LoginPage: React.FC<LoginProps> = ({
  providers,
  registerLink,
  forgotPasswordLink,
  rememberMe,
  contentProps,
  wrapperProps,
  renderContent,
  formProps,
  title,
  hideForm,
}) => {
  const theme = useMantineTheme();
  const { useForm, FormProvider } = FormContext;
  const { onSubmit: onSubmitProp, ...useFormProps } = formProps || {};
  const translate = useTranslate();
  const routerType = useRouterType();
  const Link = useLink();
  const { Link: LegacyLink } = useRouterContext();

  const ActiveLink = routerType === "legacy" ? LegacyLink : Link;

  const form = useForm({
    initialValues: {
      email: "",
      password: "",
      remember: false,
    },
    validate: {
      email: (value: any) =>
        /^\S+@\S+$/.test(value)
          ? null
          : translate("pages.login.errors.validEmail", "Invalid email address"),
      password: (value: any) => value === "",
    },
    ...useFormProps,
  });
  const { onSubmit, getInputProps } = form;

  const authProvider = useActiveAuthProvider();
  const { mutate: login, isLoading } = useLogin<LoginFormTypes>({
    v3LegacyAuthProviderCompatible: Boolean(authProvider?.isLegacy),
  });

  const PageTitle =
    title === false ? null : (
      <div style={pageTitleStyles}>
        {title ?? <ThemedTitleV2 collapsed={false} />}
      </div>
    );

  const renderProviders = () => {
    if (providers && providers.length > 0) {
      return (
        <>
          <Stack spacing={8}>
            {providers.map((provider) => {
              return (
                <Button
                  key={provider.name}
                  variant="default"
                  fullWidth
                  leftIcon={provider.icon}
                  onClick={() =>
                    login({
                      providerName: provider.name,
                    })
                  }
                >
                  {provider.label}
                </Button>
              );
            })}
          </Stack>
          {!hideForm && (
            <Divider
              my="md"
              labelPosition="center"
              label={translate("pages.login.divider", "or")}
            />
          )}
        </>
      );
    }
    return null;
  };

  const CardContent = (
    <Card style={cardStyles} {...(contentProps ?? {})}>
      <Title
        style={titleStyles}
        color={theme.colorScheme === "dark" ? "brand.5" : "brand.8"}
      >
        {translate("pages.login.title", "Sign in to your account")}
      </Title>
      <Space h="sm" />
      <Space h="lg" />
      {renderProviders()}
      {!hideForm && (
        <FormProvider form={form}>
          <form
            onSubmit={onSubmit((values: any) => {
              if (onSubmitProp) {
                return onSubmitProp(values);
              }
              return login(values);
            })}
          >
            <TextInput
              name="email"
              label={translate("pages.login.fields.email", "Email")}
              placeholder={translate("pages.login.fields.email", "Email")}
              {...getInputProps("email")}
            />
            <PasswordInput
              name="password"
              autoComplete="current-password"
              mt="md"
              label={translate("pages.login.fields.password", "Password")}
              placeholder="●●●●●●●●"
              {...getInputProps("password")}
            />
            <Box
              mt="md"
              sx={{
                display: "flex",
                alignItems: "center",
                justifyContent: "space-between",
              }}
            >
              {rememberMe ?? (
                <Checkbox
                  label={translate(
                    "pages.login.buttons.rememberMe",
                    "Remember me",
                  )}
                  size="xs"
                  {...getInputProps("remember", {
                    type: "checkbox",
                  })}
                />
              )}
              {forgotPasswordLink ?? (
                <Anchor
                  component={ActiveLink as any}
                  to="/forgot-password"
                  size="xs"
                >
                  {translate(
                    "pages.login.buttons.forgotPassword",
                    "Forgot password?",
                  )}
                </Anchor>
              )}
            </Box>
            <Button
              mt="md"
              fullWidth
              size="md"
              type="submit"
              loading={isLoading}
            >
              {translate("pages.login.signin", "Sign in")}
            </Button>
          </form>
        </FormProvider>
      )}
      {registerLink ?? (
        <Text mt="md" size="xs" align="center">
          {translate("pages.login.buttons.noAccount", "Don’t have an account?")}{" "}
          <Anchor component={ActiveLink as any} to="/register" weight={700}>
            {translate("pages.login.signup", "Sign up")}
          </Anchor>
        </Text>
      )}
    </Card>
  );

  return (
    <Box
      style={{
        ...layoutStyles,
        justifyContent: hideForm ? "flex-start" : layoutStyles.justifyContent,
        paddingTop: hideForm ? "15dvh" : layoutStyles.padding,
      }}
      {...(wrapperProps ?? {})}
    >
      {renderContent ? (
        renderContent(CardContent, PageTitle)
      ) : (
        <>
          {PageTitle}
          {CardContent}
        </>
      )}
    </Box>
  );
};