diff --git a/package-lock.json b/package-lock.json
index 5899ab2..b76baa3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33,6 +33,7 @@
"react-icons": "^5.5.0",
"react-router-dom": "^7.5.3",
"tailwindcss": "^4.1.5",
+ "uuidv4": "^6.2.13",
"zod": "^3.25.28"
},
"devDependencies": {
@@ -3265,6 +3266,12 @@
"@types/react": "^19.0.0"
}
},
+ "node_modules/@types/uuid": {
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
+ "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
+ "license": "MIT"
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz",
@@ -7952,6 +7959,26 @@
}
}
},
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/uuidv4": {
+ "version": "6.2.13",
+ "resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.2.13.tgz",
+ "integrity": "sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ==",
+ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
+ "license": "MIT",
+ "dependencies": {
+ "@types/uuid": "8.3.4",
+ "uuid": "8.3.2"
+ }
+ },
"node_modules/vite": {
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
diff --git a/package.json b/package.json
index 1c58444..e4cfbd2 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"react-icons": "^5.5.0",
"react-router-dom": "^7.5.3",
"tailwindcss": "^4.1.5",
+ "uuidv4": "^6.2.13",
"zod": "^3.25.28"
},
"devDependencies": {
diff --git a/src/assets/berti.jfif b/src/assets/berti.jfif
deleted file mode 100644
index 9d4012e..0000000
Binary files a/src/assets/berti.jfif and /dev/null differ
diff --git a/src/assets/izabel.jfif b/src/assets/izabel.jfif
deleted file mode 100644
index d4307c1..0000000
Binary files a/src/assets/izabel.jfif and /dev/null differ
diff --git a/src/assets/julia.jfif b/src/assets/julia.jfif
deleted file mode 100644
index f43acb3..0000000
Binary files a/src/assets/julia.jfif and /dev/null differ
diff --git a/src/assets/rubio.jfif b/src/assets/rubio.jfif
deleted file mode 100644
index effc2fa..0000000
Binary files a/src/assets/rubio.jfif and /dev/null differ
diff --git a/src/assets/sakamoto.jfif b/src/assets/sakamoto.jfif
deleted file mode 100644
index 696105e..0000000
Binary files a/src/assets/sakamoto.jfif and /dev/null differ
diff --git a/src/domain/knowledge-base.ts b/src/domain/knowledge-base.ts
index 906bf8f..793a789 100644
--- a/src/domain/knowledge-base.ts
+++ b/src/domain/knowledge-base.ts
@@ -10,6 +10,7 @@ export type KnowledgeBase = {
status: STATUS
files: KnowledgeBaseFile[]
totalSizeMB: number
+ keys: KnowledgeBaseKey[]
}
export type KnowledgeBaseFile = {
@@ -17,3 +18,8 @@ export type KnowledgeBaseFile = {
sizeMB: number
url: string
}
+
+export type KnowledgeBaseKey = {
+ kbKey: string
+ kbKeyAlias: string
+}
diff --git a/src/features/docs/pages/about-project.tsx b/src/features/docs/pages/about-project.tsx
new file mode 100644
index 0000000..6e49858
--- /dev/null
+++ b/src/features/docs/pages/about-project.tsx
@@ -0,0 +1,57 @@
+import { motion } from 'framer-motion'
+import { h1, h2, p } from '@/shared/components/typography'
+
+export function AboutProjectPage() {
+ return (
+
+ {h1({ children: 'Sobre o Projeto' })}
+
+ {h2({ children: 'Por que criamos o Knowly?' })}
+ {p({
+ children: (
+ <>
+ A inteligência artificial está mudando a forma como empresas
+ trabalham, trazendo mais agilidade e eficiência para o dia a dia.
+ Mas, para a maioria dos negócios, usar IA ainda é caro e complicado:
+ exige conhecimento técnico, tempo e investimento alto em tecnologia.
+ >
+ )
+ })}
+ {p({
+ children: (
+ <>
+ O Knowly nasceu para simplificar esse cenário. Queremos que qualquer
+ empresa consiga aproveitar o poder dos grandes modelos de linguagem
+ para responder dúvidas, organizar informações e automatizar tarefas,
+ sem precisar se preocupar com detalhes técnicos ou infraestrutura.
+ >
+ )
+ })}
+ {p({
+ children: (
+ <>
+ Nossa plataforma permite que você envie seus próprios documentos e,
+ em poucos cliques, já tenha uma base de conhecimento inteligente
+ pronta para ser usada no seu atendimento, site ou operação interna.
+ Tudo isso com segurança, praticidade e custos acessíveis.
+ >
+ )
+ })}
+ {p({
+ children: (
+ <>
+ O objetivo é ajudar empresas a inovar, ganhar tempo e focar no que
+ realmente importa: crescer e atender melhor seus clientes, usando IA
+ de verdade no dia a dia.
+ >
+ )
+ })}
+
+ )
+}
+
+export default AboutProjectPage
diff --git a/src/features/docs/pages/foundation-models.tsx b/src/features/docs/pages/foundation-models.tsx
new file mode 100644
index 0000000..407c874
--- /dev/null
+++ b/src/features/docs/pages/foundation-models.tsx
@@ -0,0 +1,129 @@
+import { motion } from 'framer-motion'
+import { h1, h2, p, ul, li } from '@/shared/components/typography'
+
+export function FoundationModelsPage() {
+ return (
+
+ {h1({ children: 'Modelos de Fundação AWS' })}
+
+ {h2({ children: 'O que são modelos de fundação?' })}
+ {p({
+ children: (
+ <>
+ Modelos de fundação são inteligências artificiais treinadas para
+ entender e gerar textos, responder perguntas, resumir informações e
+ até criar conteúdos. Eles servem como base para várias aplicações de
+ IA, desde chatbots até análise de documentos.
+ >
+ )
+ })}
+
+ {h2({ children: 'Principais modelos disponíveis na AWS' })}
+ {ul({
+ children: (
+ <>
+ {li({
+ children: (
+ <>
+ Amazon Titan: Modelo versátil para tarefas do
+ dia a dia, como responder perguntas, resumir textos e
+ organizar informações. É uma ótima escolha para quem busca
+ equilíbrio entre custo e desempenho.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Anthropic Claude: Ideal para conversas mais
+ longas, respostas detalhadas e situações que exigem mais
+ segurança e controle. Muito usado em chatbots avançados e
+ assistentes virtuais.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ AI21 Labs: Especialista em geração de textos
+ criativos, artigos, e até mesmo conteúdos técnicos. Indicado
+ para quem precisa de textos mais elaborados ou criativos.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Cohere: Focado em análise de linguagem,
+ classificação de textos e extração de informações. Bom para
+ automação de processos e análise de grandes volumes de dados.
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ {h2({ children: 'Quando usar cada modelo?' })}
+ {ul({
+ children: (
+ <>
+ {li({
+ children: (
+ <>
+ Precisa de respostas rápidas e gerais? Use o{' '}
+ Amazon Titan.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+
+ Vai criar um chatbot ou assistente virtual que precisa
+ conversar bastante?
+ {' '}
+ O Claude é uma ótima opção.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Quer gerar textos criativos ou técnicos?{' '}
+ Experimente o AI21 Labs.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+
+ Precisa analisar, classificar ou organizar muitos textos?
+ {' '}
+ O Cohere pode ajudar.
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ {p({
+ children: (
+ <>
+ Com esses modelos, você pode escolher a solução que mais combina com
+ o seu projeto, sem se preocupar com a complexidade técnica. Basta
+ selecionar o modelo e começar a usar!
+ >
+ )
+ })}
+
+ )
+}
+
+export default FoundationModelsPage
diff --git a/src/features/docs/pages/integration.tsx b/src/features/docs/pages/integration.tsx
new file mode 100644
index 0000000..10a5a86
--- /dev/null
+++ b/src/features/docs/pages/integration.tsx
@@ -0,0 +1,83 @@
+import { motion } from 'framer-motion'
+import { h1, h2, p, ul, li, pre } from '@/shared/components/typography'
+
+export function IntegrationPage() {
+ return (
+
+ {h1({ children: 'Como integrar com sua base de conhecimento' })}
+
+ {h2({ children: 'Integração simples via API' })}
+ {p({
+ children: (
+ <>
+ Depois de criar sua base de conhecimento no Knowly, você pode
+ integrá-la facilmente ao seu sistema usando nossa API. O
+ funcionamento é parecido com a API da OpenAI, muito usada em
+ chatbots de atendimento, como no WhatsApp.
+ >
+ )
+ })}
+
+ {h2({ children: 'Como funciona?' })}
+ {ul({
+ children: (
+ <>
+ {li({
+ children: (
+ <>
+ Você envia um prompt (mensagem ou pergunta)
+ para a API, junto com sua chave de acesso.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ A API responde com a melhor resposta baseada nos documentos
+ que você enviou para sua base.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ É possível usar essa integração em sites, sistemas internos,
+ chatbots e muito mais.
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ {h2({ children: 'Exemplo de requisição' })}
+ {pre({
+ children: `POST https://api.knowly.ai/v1/query
+Headers:
+ Authorization: Bearer SUA_CHAVE_DE_API
+Body:
+{
+ "prompt": "Como faço para atualizar meus dados cadastrais?",
+ "baseId": "sua-base-id"
+}`
+ })}
+
+ {p({
+ children: (
+ <>
+ A resposta virá em formato JSON, com o texto gerado pela IA usando o
+ conhecimento da sua base. Assim, você pode automatizar atendimentos,
+ responder dúvidas de clientes ou integrar a IA ao seu sistema de
+ forma simples e eficiente.
+ >
+ )
+ })}
+
+ )
+}
+
+export default IntegrationPage
diff --git a/src/features/docs/pages/knowledge-bases.tsx b/src/features/docs/pages/knowledge-bases.tsx
new file mode 100644
index 0000000..78192e0
--- /dev/null
+++ b/src/features/docs/pages/knowledge-bases.tsx
@@ -0,0 +1,63 @@
+import { motion } from 'framer-motion'
+import { h1, h2, p, ul, li } from '@/shared/components/typography'
+
+export function KnowledgeBasesPage() {
+ return (
+
+ {h1({ children: 'Gerenciando Bases de Conhecimento' })}
+
+ {h2({ children: 'Como criar, editar e excluir suas bases' })}
+ {p({
+ children: (
+ <>
+ Gerenciar suas bases de conhecimento no Knowly é simples e rápido.
+ Basta acessar as configurações do seu perfil após fazer login e
+ selecionar a opção "Minhas bases".
+ >
+ )
+ })}
+
+ {ul({
+ children: (
+ <>
+ {li({
+ children: (
+ <>
+ Para criar uma base: Clique em{' '}
+ "Nova base", escolha um nome e
+ envie os documentos que deseja usar. Pronto! Sua base estará
+ disponível para consultas e integrações assim que terminar de
+ ser criada.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Para editar: Selecione uma base existente na
+ lista para ver detalhes, adicionar ou remover documentos, ou
+ atualizar informações.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Para excluir: Escolha a base desejada e
+ clique em "Excluir". Confirme a
+ ação para remover a base do sistema.
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ )
+}
+
+export default KnowledgeBasesPage
diff --git a/src/features/docs/pages/playground-testing.tsx b/src/features/docs/pages/playground-testing.tsx
new file mode 100644
index 0000000..1e7a64e
--- /dev/null
+++ b/src/features/docs/pages/playground-testing.tsx
@@ -0,0 +1,68 @@
+import { motion } from 'framer-motion'
+import { h1, h2, p, ul, li } from '@/shared/components/typography'
+
+export function PlaygroundTestingPage() {
+ return (
+
+ {h1({ children: 'Testando sua Base de Conhecimento no Playground' })}
+
+ {h2({ children: 'O que é o Playground?' })}
+ {p({
+ children: (
+ <>
+ O Playground é uma área do nosso site feita para você testar, na
+ prática, as bases de conhecimento que criou. Ele funciona como um
+ chat, parecido com o ChatGPT ou o Gemini, onde você pode conversar
+ com a sua base e ver as respostas geradas pela inteligência
+ artificial.
+ >
+ )
+ })}
+
+ {h2({ children: 'Como funciona?' })}
+ {ul({
+ children: (
+ <>
+ {li({
+ children: <>Escolha qual base de conhecimento você quer testar.>
+ })}
+ {li({
+ children: (
+ <>
+ Envie perguntas ou comandos (prompts) no chat, como faria em
+ um atendimento real.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Veja as respostas geradas na hora, usando os documentos e
+ informações que você cadastrou.
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ {h2({ children: 'Por que usar o Playground?' })}
+ {p({
+ children: (
+ <>
+ O Playground é a maneira mais fácil e rápida de conferir se sua base
+ está funcionando como esperado. Você pode testar diferentes
+ perguntas, ajustar seus documentos e experimentar os modelos antes
+ de integrar a IA ao seu site ou sistema.
+ >
+ )
+ })}
+
+ )
+}
+
+export default PlaygroundTestingPage
diff --git a/src/features/docs/pages/subscription-management.tsx b/src/features/docs/pages/subscription-management.tsx
new file mode 100644
index 0000000..a6f0251
--- /dev/null
+++ b/src/features/docs/pages/subscription-management.tsx
@@ -0,0 +1,66 @@
+import { motion } from 'framer-motion'
+import { h1, h2, p, ul, li } from '@/shared/components/typography'
+
+export function SubscriptionManagementPage() {
+ return (
+
+ {h1({ children: 'Gerenciando seu Plano de Assinatura' })}
+
+ {h2({ children: 'Como alterar seu plano' })}
+ {p({
+ children: (
+ <>
+ Para gerenciar seu plano de assinatura no Knowly, é só acessar a
+ área do usuário após fazer login. No menu lateral à esquerda, clique
+ em "Assinatura".
+ >
+ )
+ })}
+ {ul({
+ children: (
+ <>
+ {li({
+ children: (
+ <>
+ Na seção "Plano atual", procure o
+ botão "Mudar plano" no canto
+ inferior direito.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Clique em "Mudar plano" para ver as
+ opções disponíveis e escolher o plano que melhor atende às
+ suas necessidades.
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Confirme a alteração e pronto! Seu novo plano já estará ativo.
+ >
+ )
+ })}
+ >
+ )
+ })}
+ {p({
+ children: (
+ <>
+ Assim, você pode ajustar sua assinatura sempre que quiser, de forma
+ rápida e sem complicação.
+ >
+ )
+ })}
+
+ )
+}
+
+export default SubscriptionManagementPage
diff --git a/src/features/home/pages/home-page.tsx b/src/features/home/pages/home-page.tsx
index c672251..3c2da9f 100644
--- a/src/features/home/pages/home-page.tsx
+++ b/src/features/home/pages/home-page.tsx
@@ -4,11 +4,6 @@ import { motion } from 'framer-motion'
import { Button } from '@/shared/components/button'
import { Accordion, AccordionItem } from '@/shared/components/accordion'
import { DotLottieReact } from '@lottiefiles/dotlottie-react'
-import berti from '@/assets/berti.jfif'
-import izabel from '@/assets/izabel.jfif'
-import rubio from '@/assets/rubio.jfif'
-import julia from '@/assets/julia.jfif'
-import sakamoto from '@/assets/sakamoto.jfif'
import { Fragment } from 'react/jsx-runtime'
import {
Card,
@@ -116,30 +111,30 @@ const process = [
const owners = [
{
name: 'Enzo Sakamoto',
- image: sakamoto,
- role: 'Estagiário de Arquitetura de Software na XP Inc.',
+ image: 'https://d1b8zs4rmj3xdl.cloudfront.net/sakamoto.jpeg',
+ role: 'Arquiteto de Software Júnior na XP Inc.',
linkedin: 'https://www.linkedin.com/in/enzosakamoto/'
},
{
name: 'Izabel Sampaio Goes',
- image: izabel,
+ image: 'https://d1b8zs4rmj3xdl.cloudfront.net/iza.jpeg',
role: 'Estagiária de Ciência de Dados e IA na Evo Systems',
linkedin: 'https://www.linkedin.com/in/izabel-sampaio-goes/'
},
{
name: 'Rafael Rubio',
- image: rubio,
+ image: 'https://d1b8zs4rmj3xdl.cloudfront.net/rubio.png',
role: 'Estagiário de Desenvolvimento de Software na Socium',
linkedin: 'https://www.linkedin.com/in/rafael-rubio-carnes-b2561b212/'
},
{
name: 'Júlia Galhardi Cerqueira',
- image: julia,
+ image: 'https://d1b8zs4rmj3xdl.cloudfront.net/julia.jpeg',
role: 'Estagiária'
},
{
name: 'Vinícius Berti',
- image: berti,
+ image: 'https://d1b8zs4rmj3xdl.cloudfront.net/berti.jpeg',
role: 'Estagiário de Dados para Antifraude na Capim',
linkedin: 'https://www.linkedin.com/in/vinicius-berti-a80354209/'
}
@@ -147,11 +142,26 @@ const owners = [
function LogoCarousel() {
const logos = [
- 'https://store-images.s-microsoft.com/image/apps.22898.1ee6619e-8cd6-4c91-a459-3abe6a6cf7b3.84da202a-9b47-4a76-be2c-79f143c64050.21add500-ed5b-42ee-b87d-ee415ae071fc',
- 'https://play-lh.googleusercontent.com/d2zqBFBEymSZKaVg_dRo1gh3hBFn7_Kl9rO74xkDmnJeLgDW0MoJD3cUx0QzZN6jdsg=w240-h480-rw',
- 'https://t2.tudocdn.net/716766?w=824&h=494',
- 'https://static.vecteezy.com/system/resources/previews/019/136/322/non_2x/amazon-logo-amazon-icon-free-free-vector.jpg',
- 'https://azure.microsoft.com/en-us/blog/wp-content/uploads/2024/02/MSFT_Azure_FEB12_319938_Blog_BlogHeader_240226_600x600_V1.jpg'
+ {
+ url: 'https://store-images.s-microsoft.com/image/apps.22898.1ee6619e-8cd6-4c91-a459-3abe6a6cf7b3.84da202a-9b47-4a76-be2c-79f143c64050.21add500-ed5b-42ee-b87d-ee415ae071fc',
+ comingSoon: true
+ }, // Meta
+ {
+ url: 'https://play-lh.googleusercontent.com/d2zqBFBEymSZKaVg_dRo1gh3hBFn7_Kl9rO74xkDmnJeLgDW0MoJD3cUx0QzZN6jdsg=w240-h480-rw',
+ comingSoon: true
+ }, // Deep Seek
+ {
+ url: 'https://static.vecteezy.com/system/resources/previews/019/136/322/non_2x/amazon-logo-amazon-icon-free-free-vector.jpg',
+ comingSoon: false
+ }, // Amazon
+ {
+ url: 'https://t2.tudocdn.net/716766?w=824&h=494',
+ comingSoon: true
+ }, // Claude Sonnet
+ {
+ url: 'https://azure.microsoft.com/en-us/blog/wp-content/uploads/2024/02/MSFT_Azure_FEB12_319938_Blog_BlogHeader_240226_600x600_V1.jpg',
+ comingSoon: false
+ } // Mistral
]
const allLogos = [...logos, ...logos, ...logos, ...logos]
return (
@@ -176,13 +186,18 @@ function LogoCarousel() {
}}
>
{allLogos.map((logo, idx) => (
-
+
+ {logo.comingSoon && (
+
+ Em breve
+
+ )}
))}
diff --git a/src/features/login/pages/login.tsx b/src/features/login/pages/login.tsx
index e6de017..171a48d 100644
--- a/src/features/login/pages/login.tsx
+++ b/src/features/login/pages/login.tsx
@@ -2,7 +2,7 @@ import { Background } from '@/shared/components/background'
import { Layout } from '@/shared/components/layout'
import { motion } from 'framer-motion'
import { Button } from '@/shared/components/button'
-import { useState } from 'react'
+import { useState, useEffect } from 'react'
import { Eye, EyeOff } from 'lucide-react'
import { BackgroundBlobs } from '@/shared/components/background-blobs'
import {
@@ -28,20 +28,63 @@ import {
Form
} from '@/shared/components/form'
import { Input } from '@/shared/components/input'
-import { Link } from 'react-router-dom'
+import { Checkbox } from '@/shared/components/checkbox'
+import { Link, useNavigate } from 'react-router-dom'
import { containerVariants, cardVariants } from '@/shared/utils/animations'
+import { useLoginUserMutation } from '@/shared/hooks/use-user'
+import toast from 'react-hot-toast'
+import { AxiosError } from 'axios'
+
+const REMEMBER_EMAIL_KEY = 'knowly_remember_email'
export function LoginPage() {
const [showPassword, setShowPassword] = useState(false)
+ const [rememberEmail, setRememberEmail] = useState(false)
+ const { mutateAsync: loginUser, isPending } = useLoginUserMutation()
+ const navigate = useNavigate()
+
+ // Get saved email before initializing form
+ const savedEmail = localStorage.getItem(REMEMBER_EMAIL_KEY)
const form = useForm({
resolver: zodResolver(loginFormSchema),
- defaultValues: loginFormInitialValues,
+ defaultValues: {
+ ...loginFormInitialValues,
+ email: savedEmail || loginFormInitialValues.email
+ },
mode: 'onBlur'
})
- const onSubmit = (values: LoginFormData) => {
- console.log(values)
+ // Set checkbox state on mount
+ useEffect(() => {
+ if (savedEmail) {
+ setRememberEmail(true)
+ }
+ }, [savedEmail])
+
+ const onSubmit = async (values: LoginFormData) => {
+ try {
+ // Save or remove email from localStorage based on checkbox
+ if (rememberEmail) {
+ localStorage.setItem(REMEMBER_EMAIL_KEY, values.email)
+ } else {
+ localStorage.removeItem(REMEMBER_EMAIL_KEY)
+ }
+
+ const response = await loginUser(values)
+ localStorage.setItem('token', response.id_token)
+ localStorage.setItem('refresh_token', response.refresh_token)
+ toast.success('Login realizado com sucesso!')
+ navigate('/bases', {
+ replace: true
+ })
+ } catch (err) {
+ const errorMessage =
+ err instanceof AxiosError && err.response?.data?.message
+ ? err.response.data.message
+ : 'Erro ao fazer login'
+ toast.error(errorMessage)
+ }
}
return (
@@ -115,9 +158,31 @@ export function LoginPage() {
)}
/>
+
+ {/* Remember Email Checkbox */}
+