diff --git a/ui/src/components/layouts/AuthLayout/AuthLayout.tsx b/ui/src/components/layouts/AuthLayout/AuthLayout.tsx index 1106ed01..ddd6d0c6 100644 --- a/ui/src/components/layouts/AuthLayout/AuthLayout.tsx +++ b/ui/src/components/layouts/AuthLayout/AuthLayout.tsx @@ -4,21 +4,22 @@ import Simple from './Simple' import View from '@/views' import { useStoreState } from '@/store' import { LAYOUT_TYPE_BLANK } from '@/constants/theme.constant' +import { HiArrowLeft } from 'react-icons/hi' const AuthLayout = () => { - const layoutType = useStoreState((state) => state.theme.layout.type) + const layoutType = useStoreState((state) => state.theme.layout.type) - return ( -
- {layoutType === LAYOUT_TYPE_BLANK ? ( - - ) : ( - - - - )} -
- ) + return ( +
+ {layoutType === LAYOUT_TYPE_BLANK ? ( + + ) : ( + + + + )} +
+ ) } export default AuthLayout diff --git a/ui/src/components/layouts/AuthLayout/Simple.tsx b/ui/src/components/layouts/AuthLayout/Simple.tsx index d9744cef..796f24d8 100644 --- a/ui/src/components/layouts/AuthLayout/Simple.tsx +++ b/ui/src/components/layouts/AuthLayout/Simple.tsx @@ -4,35 +4,41 @@ import Card from '@/components/ui/Card' import Logo from '@/components/template/Logo' import type { ReactNode, ReactElement } from 'react' import type { CommonProps } from '@/@types/common' +import { HiArrowLeft } from 'react-icons/hi' interface SimpleProps extends CommonProps { - content?: ReactNode + content?: ReactNode } const Simple = ({ children, content, ...rest }: SimpleProps) => { - return ( -
- - -
- -
-
- {content} - {children - ? cloneElement(children as ReactElement, { - contentClassName: 'text-center', - ...rest, - }) - : null} -
-
-
-
- ) + return ( +
+ + + + + + +
+ +
+
+ {content} + {children + ? cloneElement(children as ReactElement, { + contentClassName: 'text-center', + ...rest, + }) + : null} +
+
+
+
+ ) } export default Simple diff --git a/ui/src/views/auth/Login.tsx b/ui/src/views/auth/Login.tsx index 8a5e0feb..5753b667 100644 --- a/ui/src/views/auth/Login.tsx +++ b/ui/src/views/auth/Login.tsx @@ -2,6 +2,7 @@ import { FailedSignInResponse } from '@/@types/auth' import ActionLink from '@/components/shared/ActionLink' import Captcha from '@/components/shared/Captcha' import PasswordInput from '@/components/shared/PasswordInput' +import { Avatar, Select } from '@/components/ui' import Alert from '@/components/ui/Alert' import Button from '@/components/ui/Button' import Checkbox from '@/components/ui/Checkbox' @@ -16,9 +17,16 @@ import useTimeOutMessage from '@/utils/hooks/useTimeOutMessage' import { TurnstileInstance } from '@marsidev/react-turnstile' import { Field, Form, Formik } from 'formik' import { motion } from 'framer-motion' -import { useEffect, useRef, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { useNavigate } from 'react-router-dom' import * as Yup from 'yup' +import { components } from 'react-select' +import { HiArrowLeft, HiCheck } from 'react-icons/hi' +import { SelectBoxOption } from '@/shared/types' +import i18n from 'i18next' +import appConfig from '@/configs/app.config' +import { dateLocales } from '@/locales' +import dayjs from 'dayjs' type SignInFormSchema = { userName: string @@ -41,6 +49,7 @@ const validationSchema = Yup.object().shape({ }) const Login = () => { + const [loading, setLoading] = useState(false) const navigate = useNavigate() const isMultiTenant = useStoreState((a) => a.abpConfig.config?.multiTenancy.isEnabled) const { setTenantId } = useStoreActions((a) => a.auth) @@ -169,6 +178,56 @@ const Login = () => { setSubmitting(false) } + const CustomControl = ({ children, ...props }: any) => { + const selected = props.getValue()[0] + return ( + + {selected && ( + + )} + {children} + + ) + } + + const CustomSingleValue = ({ data, ...props }: any) => { + return ( + +
+ + {data.label} +
+
+ ) + } + + const CustomSelectOption = ({ innerProps, label, data, isSelected }: any) => { + return ( +
+
+ + {label} +
+ {isSelected && } +
+ ) + } + const subDomainName = getSubdomain() const tenantId = useStoreState((a) => a.auth.tenantId) ?? subDomainName const tenantStyle: React.CSSProperties | undefined = @@ -184,6 +243,49 @@ const Login = () => { } : undefined + const { config } = useStoreState((state) => state.abpConfig) + const { setLang } = useStoreActions((actions) => actions.locale) + + const languageList = config?.localization.languages + const languageOptions = useMemo(() => { + return ( + languageList?.map((lang) => ({ + label: lang.displayName, + value: lang.cultureName, + cultureName: lang.cultureName, + imgPath: `/img/countries/${lang.cultureName}.png`, + })) || [] + ) + }, [languageList]) + + const [selectedLang, setSelectedLang] = useState(() => { + const currentCulture = config?.localization?.currentCulture?.cultureName + return languageOptions.find((lang) => lang.cultureName === currentCulture) || null + }) + + const onLanguageSelect = (cultureName = appConfig.locale) => { + setLoading(true) + + const dispatchLang = () => { + i18n.changeLanguage(cultureName) + setLang(cultureName) + setLoading(false) + } + + if (dateLocales[cultureName]) { + dateLocales[cultureName]() + .then(() => { + dayjs.locale(cultureName) + dispatchLang() + }) + .catch(() => { + dispatchLang() + }) + } else { + dispatchLang() + } + } + useEffect(() => { if (!isMultiTenant) return @@ -201,14 +303,14 @@ const Login = () => { animate={{ opacity: 1, x: 0 }} transition={{ duration: 0.5, origin: 1 }} > -
-

{translate('::Abp.Account.WelcomeBack')}

+
+

{translate('::Abp.Account.WelcomeBack')}

{translate('::Abp.Account.WelcomeBack.Message')}

{isMultiTenant && ( <>
{
)} +
+ +
+