Login & register
Login / register — LoginForm
<Flex vertical justify="center" style={{ minHeight: "100vh", background: `linear-gradient(180deg, ${token.colorPrimaryBg} 0%, ${token.colorBgLayout} 45%)` }}>
<LoginForm logo={<AuditOutlined style={{ fontSize: 40, color: token.colorPrimary }} />} title="Duyệt mua sắm" subTitle="Đề xuất, duyệt và theo dõi chi tiêu mua sắm"
submitter={{ searchConfig: { submitText: "Đăng nhập" } }}
message={error ? <Alert type="error" showIcon message={error} style={{ marginBottom: 24 }} /> : undefined}
actions={<Typography.Text type="secondary">Chưa có tài khoản? <a onClick={() => nav("/register")}>Đăng ký</a></Typography.Text>}
onFinish={async (v) => { try { const r = await api.auth.login(v); signIn(r.token, r.user); nav("/"); return true; } catch (e) { setError(errMsg(e)); return false; } }}>
<ProFormText name="email" label="Email" fieldProps={{ size: "large", prefix: <MailOutlined /> }} rules={[{ required: true, type: "email" }]} />
<ProFormText.Password name="password" label="Mật khẩu" fieldProps={{ size: "large", prefix: <LockOutlined /> }} rules={[{ required: true }]} />
</LoginForm>
</Flex>- Keep
labels (accessibility + tests find fields by label). Server error goes inmessage, not a toast.
Đăng nhập — Đăng nhập: LoginForm của pro-components, có label (truy cập + test tìm theo label), lỗi server hiện trong `message`. Mở trong Playground →
Xem code (37 dòng)
// Đăng nhập: LoginForm của pro-components, có label (truy cập + test tìm theo label), lỗi server hiện trong `message`.
import { useState } from "react";
import { LoginForm, ProFormCheckbox, ProFormText } from "@ant-design/pro-components";
import { Alert, Flex, Typography, theme } from "antd";
import { AuditOutlined, LockOutlined, MailOutlined } from "@ant-design/icons";
export default function Page() {
const { token } = theme.useToken();
const [error, setError] = useState<string | null>(null);
return (
<Flex vertical justify="center" style={{ minHeight: "100vh", background: `linear-gradient(180deg, ${token.colorPrimaryBg} 0%, ${token.colorBgLayout} 45%)` }}>
<LoginForm
logo={<AuditOutlined style={{ fontSize: 40, color: token.colorPrimary }} />}
title="Duyệt mua sắm"
subTitle="Đề xuất, duyệt và theo dõi chi tiêu mua sắm"
submitter={{ searchConfig: { submitText: "Đăng nhập" } }}
initialValues={{ remember: true }}
message={error ? <Alert type="error" showIcon title={error} style={{ marginBottom: 24 }} /> : undefined}
actions={<Typography.Text type="secondary">Chưa có tài khoản? <a>Đăng ký</a></Typography.Text>}
onFinish={async (v: { email: string; password: string }) => {
// Thử: mật khẩu khác "123456" sẽ báo lỗi như server trả 401.
if (v.password !== "123456") { setError("Sai email hoặc mật khẩu"); return false; }
setError(null);
return true;
}}
>
<ProFormText name="email" label="Email" placeholder="ten@congty.vn" fieldProps={{ size: "large", prefix: <MailOutlined /> }} rules={[{ required: true, type: "email", message: "Nhập email hợp lệ" }]} />
<ProFormText.Password name="password" label="Mật khẩu" placeholder="Mật khẩu" fieldProps={{ size: "large", prefix: <LockOutlined /> }} rules={[{ required: true, message: "Nhập mật khẩu" }]} />
<div style={{ marginBlockEnd: 24 }}>
<ProFormCheckbox noStyle name="remember">Ghi nhớ đăng nhập</ProFormCheckbox>
<a style={{ float: "right" }}>Quên mật khẩu?</a>
</div>
</LoginForm>
</Flex>
);
}
Last updated on