Login con idiomas
This commit is contained in:
parent
7293385550
commit
af12f841b1
@ -50,6 +50,7 @@
|
|||||||
"cmdk": "^1.0.0",
|
"cmdk": "^1.0.0",
|
||||||
"date-fns": "^3.6.0",
|
"date-fns": "^3.6.0",
|
||||||
"embla-carousel-react": "^8.2.0",
|
"embla-carousel-react": "^8.2.0",
|
||||||
|
"flag-icons": "^7.2.3",
|
||||||
"i18next": "^23.12.2",
|
"i18next": "^23.12.2",
|
||||||
"i18next-browser-languagedetector": "^8.0.0",
|
"i18next-browser-languagedetector": "^8.0.0",
|
||||||
"joi": "^17.13.1",
|
"joi": "^17.13.1",
|
||||||
|
|||||||
200
client/src/app/auth/LoginPageWithLanguageSelector.tsx
Normal file
200
client/src/app/auth/LoginPageWithLanguageSelector.tsx
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
import { Container, FormTextField } from "@/components";
|
||||||
|
import { FormSubmitButton } from "@/components/Forms/FormSubmitButton";
|
||||||
|
import { UeckoLogo } from "@/components/UeckoLogo/UeckoLogo";
|
||||||
|
import { useLogin } from "@/lib/hooks";
|
||||||
|
import {
|
||||||
|
Alert,
|
||||||
|
AlertDescription,
|
||||||
|
AlertTitle,
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardDescription,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
Form,
|
||||||
|
} from "@/ui";
|
||||||
|
import { joiResolver } from "@hookform/resolvers/joi";
|
||||||
|
import { ILogin_DTO } from "@shared/contexts";
|
||||||
|
import Joi from "joi";
|
||||||
|
|
||||||
|
import { AlertCircleIcon, ChevronDownIcon } from "lucide-react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { SubmitHandler, useForm } from "react-hook-form";
|
||||||
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import SpanishJoiMessages from "../../spanish-joi-messages.json";
|
||||||
|
import "/node_modules/flag-icons/css/flag-icons.min.css";
|
||||||
|
|
||||||
|
type LoginDataForm = ILogin_DTO;
|
||||||
|
|
||||||
|
const languages = [
|
||||||
|
{ code: "en", name: "English", flag: () => <span className='fi fi-gb'></span> },
|
||||||
|
{ code: "es", name: "Español", flag: () => <span className='fi fi-es'></span> },
|
||||||
|
{ code: "fr", name: "Français", flag: () => <span className='fi fi-fr'></span> },
|
||||||
|
{ code: "it", name: "Italiano", flag: () => <span className='fi fi-it'></span> },
|
||||||
|
];
|
||||||
|
|
||||||
|
export const LoginPageWithLanguageSelector = () => {
|
||||||
|
const { t, i18n } = useTranslation();
|
||||||
|
const [language, setLanguage] = useState(i18n.language);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const browserLang = navigator.language.split("-")[0];
|
||||||
|
const supportedLang = languages.find((lang) => lang.code === browserLang);
|
||||||
|
if (supportedLang) {
|
||||||
|
changeLanguage(supportedLang.code);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const changeLanguage = (lng: string) => {
|
||||||
|
i18n.changeLanguage(lng);
|
||||||
|
setLanguage(lng);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { mutate: login } = useLogin({
|
||||||
|
onSuccess: (data) => {
|
||||||
|
const { success, error } = data;
|
||||||
|
if (!success && error) {
|
||||||
|
form.setError("root", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
console.debug(error);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm<LoginDataForm>({
|
||||||
|
mode: "onBlur",
|
||||||
|
defaultValues: {
|
||||||
|
email: "",
|
||||||
|
password: "",
|
||||||
|
},
|
||||||
|
resolver: joiResolver(
|
||||||
|
Joi.object({
|
||||||
|
email: Joi.string()
|
||||||
|
.email({ tlds: { allow: false } })
|
||||||
|
.required(),
|
||||||
|
password: Joi.string().min(4).alphanum().required(),
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
messages: SpanishJoiMessages,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit: SubmitHandler<LoginDataForm> = async (data) => {
|
||||||
|
login({ email: data.email, password: data.password }, {});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
variant={"full"}
|
||||||
|
className='p-0 lg:grid lg:min-h-[600px] lg:grid-cols-2 xl:min-h-[800px] h-screen '
|
||||||
|
>
|
||||||
|
<div className='flex items-center justify-center py-12 '>
|
||||||
|
<div className='mx-auto grid w-[650px] gap-6 relative '>
|
||||||
|
<div className='absolute flex space-x-2 top-4 right-4 '>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button variant='outline' className='w-[140px] justify-start'>
|
||||||
|
<span className='mr-2'>
|
||||||
|
{languages.find((lang) => lang.code === language)?.flag()}
|
||||||
|
</span>
|
||||||
|
{languages.find((lang) => lang.code === language)?.name}
|
||||||
|
<ChevronDownIcon className='w-4 h-4 ml-auto opacity-50' />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent className='w-[140px]'>
|
||||||
|
{languages.map((lang) => (
|
||||||
|
<DropdownMenuItem key={lang.code} onSelect={() => changeLanguage(lang.code)}>
|
||||||
|
<span className='mr-2'>{lang.flag()}</span>
|
||||||
|
{lang.name}
|
||||||
|
</DropdownMenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
<Card className='px-12 py-6 bg-muted/50'>
|
||||||
|
<CardHeader>
|
||||||
|
<UeckoLogo className='inline-block m-auto mb-6 align-middle max-w-32' />
|
||||||
|
<CardTitle>
|
||||||
|
<Trans i18nKey='login_page.title' />
|
||||||
|
</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
<Trans i18nKey='login_page.description' />
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<Form {...form}>
|
||||||
|
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||||
|
<div className='grid items-start gap-6'>
|
||||||
|
<div className='grid gap-6'>
|
||||||
|
<FormTextField
|
||||||
|
required
|
||||||
|
name='email'
|
||||||
|
label={t("login_page.email_label")}
|
||||||
|
type='email'
|
||||||
|
placeholder={t("login_page.email_placeholder")}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='grid gap-6'>
|
||||||
|
<FormTextField
|
||||||
|
required
|
||||||
|
name='password'
|
||||||
|
label={t("login_page.password_label")}
|
||||||
|
type='password'
|
||||||
|
/>
|
||||||
|
<div className='mb-4 -mt-2 text-sm'>
|
||||||
|
<Trans i18nKey='login_page.forgotten_password' />
|
||||||
|
<br />
|
||||||
|
<Link to='https://uecko.com/distribuidores' className='underline'>
|
||||||
|
<Trans i18nKey='login_page.contact_us' />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{form.formState.errors.root?.message && (
|
||||||
|
<Alert variant='destructive'>
|
||||||
|
<AlertCircleIcon className='w-4 h-4' />
|
||||||
|
<AlertTitle>
|
||||||
|
<Trans i18nKey='common.error' />
|
||||||
|
</AlertTitle>
|
||||||
|
<AlertDescription>{form.formState.errors.root?.message}</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<FormSubmitButton className='w-full' label={t("login_page.login")} />
|
||||||
|
|
||||||
|
<div className='mt-4 text-sm text-center'>
|
||||||
|
<Trans i18nKey='login_page.become_dealer' />
|
||||||
|
<br />
|
||||||
|
<Link to='https://uecko.com/distribuidores' className='underline'>
|
||||||
|
<Trans i18nKey='login_page.contact_us' />
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
<img className='block w-11/12 mx-auto aspect-auto' src='/img/uecko-footer_logos.jpg' />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='hidden bg-muted lg:block'>
|
||||||
|
<img
|
||||||
|
src='/img/nara2.jpg'
|
||||||
|
alt='Image'
|
||||||
|
width='1920'
|
||||||
|
height='1080'
|
||||||
|
className='h-full w-full object-cover dark:brightness-[0.2] dark:grayscale'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -3308,6 +3308,11 @@ find-up@^5.0.0:
|
|||||||
locate-path "^6.0.0"
|
locate-path "^6.0.0"
|
||||||
path-exists "^4.0.0"
|
path-exists "^4.0.0"
|
||||||
|
|
||||||
|
flag-icons@^7.2.3:
|
||||||
|
version "7.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/flag-icons/-/flag-icons-7.2.3.tgz#b67f379fa0ef28c4e605319a78035131bdd8ced7"
|
||||||
|
integrity sha512-X2gUdteNuqdNqob2KKTJTS+ZCvyWeLCtDz9Ty8uJP17Y4o82Y+U/Vd4JNrdwTAjagYsRznOn9DZ+E/Q52qbmqg==
|
||||||
|
|
||||||
flat-cache@^3.0.4:
|
flat-cache@^3.0.4:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
|
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user