From 78427b7bb57152ab477bc8514420255885ad0c4e Mon Sep 17 00:00:00 2001 From: Viet Anh Nguyen Date: Thu, 14 Dec 2023 13:26:28 +0700 Subject: [PATCH] Add login page - UI --- cope2n-fe/public/login_bg.svg | 12 ++ cope2n-fe/src/components/brand/index.tsx | 20 +- .../src/components/language-select/index.tsx | 18 +- cope2n-fe/src/layouts/main-layout.tsx | 2 +- cope2n-fe/src/locales/en/messages.json | 11 +- cope2n-fe/src/locales/vi/messages.json | 11 +- cope2n-fe/src/router/createRouter.tsx | 5 + cope2n-fe/src/router/guard-route.tsx | 2 +- cope2n-fe/src/views/login/index.tsx | 197 ++++++++++++++++++ cope2n-fe/src/views/login/style.css | 4 + 10 files changed, 262 insertions(+), 20 deletions(-) create mode 100644 cope2n-fe/public/login_bg.svg create mode 100644 cope2n-fe/src/views/login/index.tsx create mode 100644 cope2n-fe/src/views/login/style.css diff --git a/cope2n-fe/public/login_bg.svg b/cope2n-fe/public/login_bg.svg new file mode 100644 index 0000000..ac2459b --- /dev/null +++ b/cope2n-fe/public/login_bg.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/cope2n-fe/src/components/brand/index.tsx b/cope2n-fe/src/components/brand/index.tsx index e947b2a..040ecd7 100644 --- a/cope2n-fe/src/components/brand/index.tsx +++ b/cope2n-fe/src/components/brand/index.tsx @@ -1,4 +1,4 @@ -import { Typography } from 'antd'; +import { Typography } from "antd"; export const Brand = ({ collapsed, @@ -13,15 +13,21 @@ export const Brand = ({ rows: 1, }} style={{ - margin: 12, + marginTop: 3, + marginLeft: 12, + marginRight: 12, + paddingTop: 18, + paddingBottom: 18, letterSpacing: 2, - borderRadius: 4, - color: 'wheat', - textAlign: 'center', - border: isBordered ? '4px solid wheat' : 'unset', + borderBottomLeftRadius: 10, + borderBottomRightRadius: 10, + color: "#fff", + textAlign: "center", + backgroundColor: "rgb(0, 106, 255)", + fontSize: 32, }} > - {collapsed ? 'O' : 'OCR'} + {collapsed ? "O" : "OCR"} ); }; diff --git a/cope2n-fe/src/components/language-select/index.tsx b/cope2n-fe/src/components/language-select/index.tsx index de79617..6e26671 100644 --- a/cope2n-fe/src/components/language-select/index.tsx +++ b/cope2n-fe/src/components/language-select/index.tsx @@ -1,8 +1,8 @@ -import { Segmented } from 'antd'; -import styled from 'styled-components'; -import { useLocalStorage } from 'usehooks-ts'; -import { LOCALE_KEY } from '../../consts'; -import { dynamicActivate, getLocale } from '../../i18n'; +import { Segmented } from "antd"; +import styled from "styled-components"; +import { useLocalStorage } from "usehooks-ts"; +import { LOCALE_KEY } from "../../consts"; +import { dynamicActivate, getLocale } from "../../i18n"; const StyledSegmented = styled(Segmented)` & label.ant-segmented-item.ant-segmented-item-selected, @@ -23,12 +23,12 @@ export const LanguageSelect = () => { - + {/* */} CMC Account?": "Login with  <0>CMC Account?", "Name": "Name", "Nation": "Nation", "Nationality": "Nationality", @@ -58,8 +63,11 @@ "No response.": "No response.", "Number": "Number", "Other Documents": "Other Documents", + "Password": "Password", "Please do not leave the label of extracted fields empty": "Please do not leave the label of extracted fields empty", "Please draw at least 1 box of extracted field": "Please draw at least 1 box of extracted field", + "Please specify a password": "Please specify a password", + "Please specify a username": "Please specify a username", "Please, specify a template name.": "Please, specify a template name.", "Rank": "Rank", "Refresh": "Refresh", @@ -92,7 +100,8 @@ "Update template successfully.": "Update template successfully.", "Upload file validation": "Upload file validation", "Uploaded image is not match with template.": "Uploaded image is not match with template.", - "VAT Invoice": "VAT Invoice", + "User log in successfully": "User log in successfully", + "Username": "Username", "VAT amount": "VAT amount", "Value": "Value", "You are not allowed to create more than {0} templates! Please contact us for further support.": "You are not allowed to create more than {0} templates! Please contact us for further support.", diff --git a/cope2n-fe/src/locales/vi/messages.json b/cope2n-fe/src/locales/vi/messages.json index 733f716..d2fce32 100644 --- a/cope2n-fe/src/locales/vi/messages.json +++ b/cope2n-fe/src/locales/vi/messages.json @@ -19,6 +19,7 @@ "Confirm": "Xác nhận", "Copied!": "Đã sao chép", "Copy": "Sao chép", + "Could not login with provided username and password!": "", "Create Template": "Tạo mẫu tài liệu", "Create template error: Extracted fields must have unique labels.": "Tạo mẫu tài liệu lỗi: Các trường thông tin trích xuất phải có nhãn khác nhau.", "Create template error: {0}": "Tạo mẫu tài liệu lỗi: {0}", @@ -43,12 +44,16 @@ "Form number": "Số mẫu", "Home Town": "Quê quán", "ID Card": "Căn cước công dân", + "Intelligent Document Processing Solutions": "", "Invoice": "Hóa đơn", "Invoice number": "Số hóa đơn", "Issued By": "Nơi cấp", "Key Information Extraction": "Trích xuất thông tin", "Label": "Nhãn", "Label of extracted field must not have more than 255 characters": "Độ dài nhãn của trường thông tin trích xuất không được vượt quá 255 kí tự", + "Language": "", + "Login": "", + "Login with  <0>CMC Account?": "", "Name": "Tên", "Nation": "Dân tộc", "Nationality": "Quốc tịch", @@ -58,8 +63,11 @@ "No response.": "Không có kết quả", "Number": "Số", "Other Documents": "Các tài liệu khác", + "Password": "", "Please do not leave the label of extracted fields empty": "Vui lòng không bỏ trống nhãn của trường thông tin trích xuất", "Please draw at least 1 box of extracted field": "Vui lòng vẽ ít nhất một hình cho việc trích xuất thông tin", + "Please specify a password": "", + "Please specify a username": "", "Please, specify a template name.": "Vui lòng nhập tên mẫu", "Rank": "Hạng", "Refresh": "Tải lại", @@ -92,7 +100,8 @@ "Update template successfully.": "Sửa mẫu tài liệu thành công.", "Upload file validation": "Xác thực tệp tải lên", "Uploaded image is not match with template.": "Ảnh được chọn không khớp với mẫu.", - "VAT Invoice": "Hóa đơn VAT", + "User log in successfully": "", + "Username": "", "VAT amount": "Tổng tiền VAT", "Value": "Giá trị", "You are not allowed to create more than {0} templates! Please contact us for further support.": "Hệ thống không cho phép tạo nhiều hơn {0} mẫu tài liệu. Vui lòng liên hệ chúng tôi để được hỗ trợ thêm.", diff --git a/cope2n-fe/src/router/createRouter.tsx b/cope2n-fe/src/router/createRouter.tsx index d0b51c4..6594cb1 100644 --- a/cope2n-fe/src/router/createRouter.tsx +++ b/cope2n-fe/src/router/createRouter.tsx @@ -6,6 +6,7 @@ import DriverLicensePage from '../views/driver-license'; import IDCardPage from '../views/id-card'; import InvoicePage from '../views/invoice'; import OtherDocumentsPage from '../views/other-documents'; +import LoginPage from '../views/login'; import { PrivateRoute } from './guard-route'; const ConfigTemplatePage = React.lazy(() => import('../views/config-template')); @@ -28,6 +29,10 @@ export function createRouter() { /> ), }, + { + path: '/login', + element: , + }, { path: '/error/401', element: ( diff --git a/cope2n-fe/src/router/guard-route.tsx b/cope2n-fe/src/router/guard-route.tsx index fd1922e..9ec40b9 100644 --- a/cope2n-fe/src/router/guard-route.tsx +++ b/cope2n-fe/src/router/guard-route.tsx @@ -31,5 +31,5 @@ export function PrivateRoute({ return <>{element}; } - return ; + return ; } diff --git a/cope2n-fe/src/views/login/index.tsx b/cope2n-fe/src/views/login/index.tsx new file mode 100644 index 0000000..cc58448 --- /dev/null +++ b/cope2n-fe/src/views/login/index.tsx @@ -0,0 +1,197 @@ +import { LockOutlined, UserOutlined } from "@ant-design/icons"; +import { t, Trans } from "@lingui/macro"; +import { useLingui } from "@lingui/react"; +import { + Button, + Col, + Form, + FormProps, + Input, + notification, + Row, + Typography, +} from "antd"; +import { AxiosError } from "axios"; +import { useEffect, useState } from "react"; +import styled from "styled-components"; +import { LanguageSelect } from "../../components/language-select"; +import { TOKEN_KEY } from "../../consts"; +import "./style.css"; + +export const DIVERGE_FORM_ICON_COLOR = "rgba(0, 0, 0, 0.25)"; + +export function getErrorMessage(error: any) { + if (error instanceof AxiosError) { + return error.response?.data?.message; + } + + return ""; +} + +export interface LogInPayload { + username: string; + password: string; +} + +const StyledLoginContainer = styled.div` + width: 100%; + height: 100%; + background-image: url(/login_bg.svg); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + display: flex; + justify-content: center; + align-items: center; + position: relative; +`; + +const StyledFormContainer = styled(Form)` + .login-form__title { + color: white; + text-align: justify; + font-size: 52px; + margin-bottom: 0; + } + + .login-form__subtitle { + color: #84b1e3; + text-align: right; + font-weight: 300; + margin-top: 0 !important; + } + + .login-form__form-title { + color: white; + text-align: right; + font-weight: 400; + margin-top: 0.8em !important; + } + + .ant-form-item-control-input .ant-input-affix-wrapper { + border: none; + } + + .login-form__helper-text { + font-size: 18px; + color: #83afdf; + } + + .login-form__submit-button { + display: block; + width: 100%; + } + + a { + color: white; + text-decoration: underline; + } +`; + +export default function LoginPage() { + const { i18n } = useLingui(); + const [isAuthenticating, setIsAuthenticating] = useState(false); + + useEffect(() => { + const token = localStorage.getItem(TOKEN_KEY); + if (token) { + window.location.href = "/"; + } + }, []); + + const handleLogin: FormProps["onFinish"] = async (payload) => { + setIsAuthenticating(true); + try { + const resp = await fetch("/api/ctel/login/", { + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + method: "POST", + body: JSON.stringify(payload), + }); + const message = await resp.json(); + if (!resp.ok) { + throw new Error(message?.detail); + } + let token = message?.token || ""; + token = token.trim(); + localStorage.setItem(TOKEN_KEY, JSON.stringify(token)); + notification.success({ + message: t(i18n)`User log in successfully`, + }); + setTimeout(() => { + window.location.href = "/"; + }, 1000); + } catch (error) { + setIsAuthenticating(false); + notification.error({ + message: t(i18n)`Could not login with provided username and password!`, + }); + } + }; + + return ( + + + + OCR APIs + + + Intelligent Document Processing Solutions + + + Login + + + + } + placeholder={t(i18n)`Username`} + size="large" + /> + + + + } + placeholder={t(i18n)`Password`} + size="large" + /> + + + + + + + + ); +} diff --git a/cope2n-fe/src/views/login/style.css b/cope2n-fe/src/views/login/style.css new file mode 100644 index 0000000..0fb35bf --- /dev/null +++ b/cope2n-fe/src/views/login/style.css @@ -0,0 +1,4 @@ +#root { + min-height: 100%; + height: 100%; +} \ No newline at end of file