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 (
+
+
+
+ )
+ }
+
+ const CustomSelectOption = ({ innerProps, label, data, isSelected }: any) => {
+ return (
+
+ )
+ }
+
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 && (
<>
{
>
)}
+
+
+
+
+
{
{translate('::Abp.Account.RememberMe')}
- {translate('::Abp.Account.ForgotPassword')}
+
+ {translate('::Abp.Account.ForgotPassword')}
+
{showCaptcha && (
{
{translate('::Abp.Account.SignUp.Message')}
-
{translate('::Abp.Account.Register')}
+
+ {translate('::Abp.Account.Register')}
+