Versão 18h39 06/03
This commit is contained in:
parent
20fc4e91f5
commit
3d67602759
@ -1,33 +0,0 @@
|
||||
<template>
|
||||
<v-card
|
||||
class="pa-4"
|
||||
:class="{ 'striped-bg': item.striped }"
|
||||
:color="item.color"
|
||||
outlined
|
||||
>
|
||||
<v-card-text class="text-center text-white text-h6 card">
|
||||
{{ item.name }}
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
defineProps({
|
||||
item: Object,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.card {
|
||||
color: #6c00b5!important;
|
||||
}
|
||||
|
||||
.striped-bg {
|
||||
|
||||
border-radius: 50px;
|
||||
background: linear-gradient(145deg, #eeeded, #ffffff);
|
||||
box-shadow: 20px 20px 60px #d9d9d9,
|
||||
-20px -20px 60px #ffffff;
|
||||
}
|
||||
</style>
|
||||
@ -1,227 +0,0 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useChatStore
|
||||
|
||||
} from '../stores/chatstore';
|
||||
const chatStore = useChatStore()
|
||||
|
||||
// Variáveis de controle do Drawer e do Mini Variant
|
||||
const isDrawerOpen = ref(true)
|
||||
const isMiniVariant = ref(false)
|
||||
const inputMessage = ref('')
|
||||
|
||||
// Funções de controle do Drawer
|
||||
const toggleDrawer = () => {
|
||||
isDrawerOpen.value = !isDrawerOpen.value
|
||||
isMiniVariant.value = !isMiniVariant.value
|
||||
}
|
||||
|
||||
// Selecionar um chat da lista
|
||||
const selectChat = (index) => {
|
||||
chatStore.selectedChatIndex = index
|
||||
}
|
||||
|
||||
// Criar um novo chat
|
||||
const createNewChat = () => {
|
||||
const newChatName = `Chat ${chatStore.chatList.length + 1}`
|
||||
chatStore.chatList.push({ id: `chat${chatStore.chatList.length + 1}`, name: newChatName, messages: [] })
|
||||
chatStore.selectedChatIndex = chatStore.chatList.length - 1
|
||||
}
|
||||
|
||||
// Salvar nome do chat
|
||||
const saveChatName = (index) => {
|
||||
if (chatStore.chatList[index].name.trim() !== '') {
|
||||
chatStore.chatList[index].name = chatStore.chatList[index].name.trim()
|
||||
}
|
||||
}
|
||||
|
||||
// Enviar uma mensagem
|
||||
const sendMessage = () => {
|
||||
if (inputMessage.value.trim() !== '') {
|
||||
chatStore.chatList[chatStore.selectedChatIndex].messages.push({ text: inputMessage.value, isUser: true })
|
||||
inputMessage.value = ''
|
||||
|
||||
setTimeout(() => {
|
||||
chatStore.chatList[chatStore.selectedChatIndex].messages.push({
|
||||
text: 'Esta é uma resposta automática.',
|
||||
isUser: false
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
// Carregar os chats do usuário no onMounted
|
||||
onMounted(async () => {
|
||||
const userId = 'user123' // Esse id viria do sistema de autenticação
|
||||
await chatStore.loadChats(userId)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container fluid no-gutters class="chat">
|
||||
<!-- Drawer Lateral -->
|
||||
<v-navigation-drawer v-model="isDrawerOpen" :mini-variant="isMiniVariant" app permanent>
|
||||
<v-list>
|
||||
<v-list-item v-if="!isMiniVariant">
|
||||
<v-row align="center" justify="space-between" style="width: 100%">
|
||||
<v-col cols="auto">
|
||||
<v-list-item-title class="text-h6">Chats</v-list-item-title>
|
||||
</v-col>
|
||||
<v-col cols="auto">
|
||||
<v-icon @click="createNewChat" style="padding-left: 25pt;">mdi-chat-plus-outline</v-icon>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-list-item>
|
||||
|
||||
<!-- Lista de chats -->
|
||||
<v-list-item v-for="(chat, index) in chatStore.chatList" :key="chat.id" @click="selectChat(index)"
|
||||
:class="{ 'chat-selected': chatStore.selectedChatIndex === index }" v-if="!isMiniVariant">
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
<v-textarea v-model="chat.name" @focus="chat.isUnderlined = true" @blur="chat.isUnderlined = false"
|
||||
hide-details variant="plain" class="mr-2" :class="{ 'underline': chat.isUnderlined }"
|
||||
@keyup.enter="saveChatName(index)" placeholder="Novo nome" auto-grow rows="1" max-rows="5" />
|
||||
</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
|
||||
<!-- Barra de aplicação com o título do chat selecionado -->
|
||||
<v-app-bar app flat>
|
||||
<template v-if="isMiniVariant">
|
||||
<v-btn @click="createNewChat" icon>
|
||||
<v-icon>mdi-chat-plus-outline</v-icon>
|
||||
</v-btn>
|
||||
<v-btn @click="toggleDrawer" icon>
|
||||
<v-icon>mdi-menu</v-icon>
|
||||
</v-btn>
|
||||
<h2 class="text-h5 ml-2">{{ chatStore.chatList[chatStore.selectedChatIndex]?.name }}</h2>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-btn @click="toggleDrawer" icon>
|
||||
<v-icon>mdi-menu</v-icon>
|
||||
</v-btn>
|
||||
<h2 class="text-h5 ml-2">{{ chatStore.chatList[chatStore.selectedChatIndex]?.name }}</h2>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
|
||||
<!-- Conteúdo do chat -->
|
||||
<v-col cols="12" lg="6" xs="10" offset-lg="3" offset-xs="1" class="chat-container">
|
||||
<div class="chat-messages flex-grow-1 overflow-y-auto">
|
||||
<v-list>
|
||||
<v-list-item-group>
|
||||
<v-list-item v-for="(message, index) in chatStore.chatList[chatStore.selectedChatIndex]?.messages" :key="index">
|
||||
<v-list-item-content>
|
||||
<v-row>
|
||||
<v-col cols="12" v-if="message.isUser">
|
||||
<v-row justify="end">
|
||||
<v-col cols="8">
|
||||
<v-card class="user-message" outlined>
|
||||
<v-card-text>{{ message.text }}</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" v-else>
|
||||
<v-row justify="start">
|
||||
<v-col cols="8">
|
||||
<v-card class="received-message" outlined>
|
||||
<v-card-text>{{ message.text }}</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list-item-group>
|
||||
</v-list>
|
||||
</div>
|
||||
</v-col>
|
||||
|
||||
<!-- Barra de entrada para nova mensagem -->
|
||||
<v-app-bar location="bottom" flat>
|
||||
<v-row align="center">
|
||||
<v-col cols="10" lg="6" offset="1" offset-lg="3">
|
||||
<v-textarea class="input-message" v-model="inputMessage" @keyup.enter="sendMessage"
|
||||
label="Digite sua mensagem" outlined hide-details prepend-inner-icon="mdi-send"
|
||||
@click:append-outer="sendMessage" rows="1" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-app-bar>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
|
||||
<style scoped>
|
||||
/* Estilo para as mensagens recebidas */
|
||||
.input-message {
|
||||
background-color: #f1f1f1;
|
||||
border-top-left-radius: 16px;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-top-right-radius: 16px;
|
||||
border-bottom-right-radius: 0px;
|
||||
text-align: center;
|
||||
margin-bottom: 15pt;
|
||||
max-width: 100%;
|
||||
/* Limita para que o texto não ocupe toda a linha */
|
||||
box-shadow: none;
|
||||
/* Remove a sombra */
|
||||
}
|
||||
|
||||
/* Estilo para as mensagens do usuário */
|
||||
.user-message {
|
||||
background-color: #e3f2fd;
|
||||
border-top-left-radius: 16px;
|
||||
border-bottom-left-radius: 16px;
|
||||
border-top-right-radius: 16px;
|
||||
border-bottom-right-radius: 0px;
|
||||
text-align: end;
|
||||
max-width: 100%;
|
||||
/* Limita para que o texto não ocupe toda a linha */
|
||||
box-shadow: none;
|
||||
/* Remove a sombra */
|
||||
}
|
||||
|
||||
/* Estilo para as mensagens recebidas */
|
||||
.received-message {
|
||||
background-color: #f1f1f1;
|
||||
border-top-left-radius: 16px;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-top-right-radius: 16px;
|
||||
border-bottom-right-radius: 16px;
|
||||
text-align: start;
|
||||
max-width: 100%;
|
||||
/* Limita para que o texto não ocupe toda a linha */
|
||||
box-shadow: none;
|
||||
/* Remove a sombra */
|
||||
}
|
||||
|
||||
.chat-selected {
|
||||
background-color: #e0f7fa;
|
||||
}
|
||||
|
||||
.v-navigation-drawer {
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.chat {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
height: calc(80vh - 70px);
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
@ -1,111 +1,105 @@
|
||||
<template>
|
||||
<v-navigation-drawer class="body sidebar-navigation" v-model="drawer" app>
|
||||
<v-navigation-drawer
|
||||
class="sidebar-navigation"
|
||||
v-model="drawer"
|
||||
app
|
||||
>
|
||||
<v-list>
|
||||
<v-list-item
|
||||
v-for="(item, index) in filteredMenuItems"
|
||||
:key="index"
|
||||
:to="{ path: item.path }"
|
||||
<v-list-item
|
||||
v-for="(item, index) in filteredMenuItems"
|
||||
:key="index"
|
||||
:to="{ path: item.path }"
|
||||
exact
|
||||
class="menu-item"
|
||||
>
|
||||
<v-icon>{{ item.icon }}</v-icon>
|
||||
<!-- Alterado para usar v-list-item-content apenas com texto -->
|
||||
<v-list-item-content>
|
||||
<span>{{ item.title }}</span>
|
||||
</v-list-item-content>
|
||||
<template v-slot:prepend>
|
||||
<v-icon>{{ item.icon }}</v-icon>
|
||||
</template>
|
||||
<v-list-item-title>{{ item.title }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useAuthStore } from '../stores/auth' // Importa a store de autenticação
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useAuthStore } from '../stores/auth'; // Importa a store de autenticação
|
||||
|
||||
const drawer = ref(true)
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
const drawer = ref(true);
|
||||
const router = useRouter();
|
||||
const authStore = useAuthStore();
|
||||
|
||||
// A função getPermissionsByRole retorna as permissões específicas de um papel
|
||||
// Aqui estamos pegando as permissões para "Dashboard"
|
||||
const dashboardPermissions = authStore.getPermissionsByRole('Dashboard')
|
||||
console.log('Permissões do Dashboard:', dashboardPermissions) // Log para verificar as permissões
|
||||
// Debug: Verificar se a store está sendo carregada corretamente
|
||||
console.log('Auth Store:', authStore);
|
||||
console.log('Função getPermissionsByRole:', authStore.getPermissionsByRole);
|
||||
|
||||
// Itens do menu, agora com os itens atualizados: home, dashboard, analytics, reports, testing, users
|
||||
// Obtém as permissões do usuário para "Dashboard"
|
||||
const dashboardPermissions = authStore.getPermissionsByRole('Dashboard') || [];
|
||||
console.log('Permissões do Dashboard:', dashboardPermissions); // Log para verificar as permissões
|
||||
|
||||
// Itens do menu
|
||||
const menuItems = [
|
||||
{ title: 'Home', path: '/dashboard/home', icon: 'mdi mdi-home-circle', requiredPermission: 'read' },
|
||||
{ title: 'Dashboard', path: '/dashboard', icon: 'mdi mdi-view-dashboard', requiredPermission: 'read' },
|
||||
{ title: 'Analytics', path: '/dashboard/analytics', icon: 'mdi-chart-box', requiredPermission: 'read' },
|
||||
{ title: 'Relatórios', path: '/dashboard/reports', icon: 'mdi-file-chart', requiredPermission: 'read' },
|
||||
{ title: 'Testes', path: '/dashboard/testing', icon: 'mdi-flask', requiredPermission: 'write' },
|
||||
{ title: 'Gerenciamento de Usuários', path: '/dashboard/users', icon: 'mdi-account-group', requiredPermission: 'write' }
|
||||
]
|
||||
{ title: 'Perfil', path: '/dashboard/profile', icon: 'mdi-account', requiredPermission: 'read' },
|
||||
{ title: 'Configurações', path: '/dashboard/settings', icon: 'mdi-cog', requiredPermission: 'write' },
|
||||
{ title: 'Usuários', path: '/dashboard/users', icon: 'mdi-account-multiple-outline', requiredPermission: 'write' },
|
||||
{ title: 'Train', path: '/dashboard/train', icon: 'mdi mdi-thought-bubble', requiredPermission: 'write' },
|
||||
];
|
||||
|
||||
// Função para filtrar os itens de menu com base nas permissões do usuário para 'Dashboard'
|
||||
// Filtra os itens de menu com base nas permissões do usuário
|
||||
const filteredMenuItems = computed(() => {
|
||||
const filteredItems = menuItems.filter(item => dashboardPermissions.includes(item.requiredPermission))
|
||||
console.log('Itens do Menu Filtrados:', filteredItems) // Log para verificar os itens filtrados
|
||||
return filteredItems
|
||||
})
|
||||
|
||||
// Função para ativar/desativar o drawer
|
||||
const toggleDrawer = () => {
|
||||
drawer.value = !drawer.value
|
||||
}
|
||||
const filteredItems = menuItems.filter(item => dashboardPermissions.includes(item.requiredPermission));
|
||||
console.log('Itens do Menu Filtrados:', filteredItems); // Log para verificar os itens filtrados
|
||||
return filteredItems.length > 0 ? filteredItems : menuItems; // Exibir todos temporariamente se vazio
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Estilo para o menu lateral */
|
||||
.sidebar-navigation {
|
||||
background: linear-gradient(145deg, #1a237e 0%, #0d47a1 100%);
|
||||
}
|
||||
|
||||
.v-navigation-drawer {
|
||||
border-style: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
/* Estilo para os itens de menu */
|
||||
.v-list-item {
|
||||
color: rgba(108, 0, 181);
|
||||
color: white;
|
||||
transition: all 0.3s ease;
|
||||
border-style: solid;
|
||||
border-radius: 15px;
|
||||
margin: 8px 0;
|
||||
margin: 8px 16px;
|
||||
padding: 10px 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.v-list-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
color: rgba(76, 201, 240);
|
||||
border-radius: 15px !important;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: #4cc9f0;
|
||||
margin-left: 25px;
|
||||
border-radius: 50px;
|
||||
background: linear-gradient(145deg, #eeeded, #ffffff);
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
/* Estilo para o item de menu ativo */
|
||||
.v-list-item--active {
|
||||
background-color: #4cc9f0 !important;
|
||||
color: white !important;
|
||||
border-radius: 15px !important;
|
||||
margin-left: 25px;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
/* Estilo para o conteúdo do item de menu */
|
||||
.v-list-item-content {
|
||||
margin-left: 16px;
|
||||
letter-spacing: 0.5px;
|
||||
/* Estilo para os ícones */
|
||||
.v-list-item .v-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
/* Estilo para o botão de recolher */
|
||||
/* Estilo para o botão de recolher (se adicionado futuramente) */
|
||||
.v-btn {
|
||||
background: linear-gradient(145deg, #2196f3 0%, #1565c0 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Estilo para o avatar */
|
||||
/* Estilo para o avatar (se adicionado futuramente) */
|
||||
.gradient-avatar {
|
||||
background: linear-gradient(145deg, #2196f3 0%, #1565c0 100%);
|
||||
}
|
||||
@ -113,9 +107,11 @@ const toggleDrawer = () => {
|
||||
.profile-section {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
cursor: pointer;
|
||||
padding: 16px;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.profile-section:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
@ -8,17 +8,13 @@ import Settings from '../views/Settings.vue'
|
||||
import Users from '../views/Users.vue'
|
||||
import UserEditPage from '../views/UserEditPage.vue'
|
||||
import Train from '../views/Train.vue'
|
||||
import DashboardView from '../views/DashboardView.vue'
|
||||
import Chat from '../views/Chat.vue'
|
||||
import Home from '../views/Home.vue'
|
||||
import Register from '../views/Register.vue'
|
||||
|
||||
|
||||
const routes = [
|
||||
{ path: '/', redirect: '/login' },
|
||||
{ path: '/login', component: Login },
|
||||
|
||||
{ path: '/register', component: Register},
|
||||
|
||||
|
||||
{
|
||||
path: '/dashboard',
|
||||
@ -29,10 +25,7 @@ const routes = [
|
||||
{ path: 'profile', name: 'profile', component: Profile },
|
||||
{ path: 'settings', name: 'settings', component: Settings },
|
||||
{ path: 'users', name: 'users', component: Users },
|
||||
{ path: 'train', name: 'train', component: Train},
|
||||
{ path: 'dashboardview', name: 'dashboard-view', component: DashboardView},
|
||||
{ path: 'chat', name: 'chat', component: Chat },
|
||||
|
||||
{ path: 'train', name: 'train', component: Train},
|
||||
|
||||
{
|
||||
path: 'users/edit/:id', // Removido `/` do início para alinhar ao filho de dashboard
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
<template>
|
||||
|
||||
<v-container>
|
||||
<ChatComponent /> <!-- Adiciona o componente de chat aqui -->
|
||||
</v-container>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ChatComponent from '../components/ChatComponent.vue' // Importa o componente de chat
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Adicione estilos se necessário */
|
||||
</style>
|
||||
@ -1,16 +0,0 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col v-for="(item, index) in dashboardStore.items" :key="index" cols="12" md="4">
|
||||
<CardItem :item="item" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useDashboardStore } from '../stores/useDashboardStore';
|
||||
import CardItem from '../components/CardItem.vue'
|
||||
|
||||
const dashboardStore = useDashboardStore();
|
||||
</script>
|
||||
@ -54,7 +54,7 @@ export default {
|
||||
return {
|
||||
quickStats: [
|
||||
{ title: 'Câmeras Ativas', value: 0, icon: 'mdi-cctv', color: 'success' },
|
||||
{ title: 'Modelos AI', value: 0, icon: 'mdi-brain', color: 'primary' },
|
||||
{ title: 'Modelos', value: 0, icon: 'mdi-brain', color: 'primary' },
|
||||
{ title: 'Alertas 24h', value: 0, icon: 'mdi-bell', color: 'warning' },
|
||||
{ title: 'Usuários', value: 0, icon: 'mdi-account-group', color: 'info' }
|
||||
],
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
<!-- src/views/Login.vue -->
|
||||
<template>
|
||||
<div class="login-container">
|
||||
<div class="login-wrapper">
|
||||
@ -11,26 +10,11 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Right Side: Login/Register Form -->
|
||||
<div class="login-card">
|
||||
<div class="tab-buttons">
|
||||
<button
|
||||
:class="['tab-btn', { active: currentTab === 'login' }]"
|
||||
@click="currentTab = 'login'"
|
||||
>
|
||||
Sign in
|
||||
</button>
|
||||
<button
|
||||
:class="['tab-btn', { active: currentTab === 'register' }]"
|
||||
@click="currentTab = 'register'"
|
||||
>
|
||||
Register
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Login Form -->
|
||||
<div v-if="currentTab === 'login'" class="form-container">
|
||||
<h3 class="login-title">Bem-vindo</h3> <p class="login-sub-title">Faça login para continuar</p>
|
||||
<!-- Login Form -->
|
||||
<div class="login-card">
|
||||
<div class="form-container">
|
||||
<h3 class="login-title">Bem-vindo</h3>
|
||||
<p class="login-sub-title">Faça login para continuar</p>
|
||||
<form @submit.prevent="handleLogin" class="login-form">
|
||||
|
||||
<!-- Email Input -->
|
||||
@ -87,92 +71,6 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Register Form -->
|
||||
<div v-if="currentTab === 'register'" class="form-container">
|
||||
<h3 class="register-title">Criar Conta</h3>
|
||||
<p class="register-sub-title">Preencha os dados para se registrar</p>
|
||||
<form @submit.prevent="handleRegister" class="login-form">
|
||||
|
||||
<!-- Name Input -->
|
||||
<div class="form-group">
|
||||
<label for="register-name">Nome</label>
|
||||
<input
|
||||
id="register-name"
|
||||
v-model="name"
|
||||
type="text"
|
||||
placeholder="Digite seu nome completo"
|
||||
:class="{'input-error': nameError}"
|
||||
@blur="validateName"
|
||||
/>
|
||||
<span v-if="nameError" class="error-message">
|
||||
{{ nameError }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Email Input -->
|
||||
<div class="form-group">
|
||||
<label for="register-email">Email</label>
|
||||
<input
|
||||
id="register-email"
|
||||
v-model="registerEmail"
|
||||
type="email"
|
||||
placeholder="Digite seu email"
|
||||
:class="{'input-error': registerEmailError}"
|
||||
@blur="validateRegisterEmail"
|
||||
/>
|
||||
<span v-if="registerEmailError" class="error-message">
|
||||
{{ registerEmailError }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Password and Confirm Password Inputs (side by side) -->
|
||||
<div class="password-row">
|
||||
<!-- Password Input -->
|
||||
<div class="form-group password-field">
|
||||
<label for="register-password">Senha</label>
|
||||
<input
|
||||
id="register-password"
|
||||
v-model="registerPassword"
|
||||
type="password"
|
||||
placeholder="Digite sua senha"
|
||||
:class="{'input-error': registerPasswordError}"
|
||||
@blur="validateRegisterPassword"
|
||||
/>
|
||||
<span v-if="registerPasswordError" class="error-message">
|
||||
{{ registerPasswordError }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password Input -->
|
||||
<div class="form-group password-field">
|
||||
<label for="confirm-password">Confirmar Senha</label>
|
||||
<input
|
||||
id="confirm-password"
|
||||
v-model="confirmPassword"
|
||||
type="password"
|
||||
placeholder="Confirme sua senha"
|
||||
:class="{'input-error': confirmPasswordError}"
|
||||
@blur="validateConfirmPassword"
|
||||
/>
|
||||
<span v-if="confirmPasswordError" class="error-message">
|
||||
{{ confirmPasswordError }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Register Button -->
|
||||
<div class="button-group">
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
:disabled="!isRegisterFormValid"
|
||||
>
|
||||
Registrar
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -188,25 +86,12 @@ import { useAuthStore } from '../stores/auth'
|
||||
const router = useRouter()
|
||||
const authStore = useAuthStore()
|
||||
|
||||
// Current tab
|
||||
const currentTab = ref('login')
|
||||
|
||||
// Login Form Fields
|
||||
const email = ref('')
|
||||
const password = ref('')
|
||||
const emailError = ref('')
|
||||
const passwordError = ref('')
|
||||
|
||||
// Register Form Fields
|
||||
const name = ref('')
|
||||
const registerEmail = ref('')
|
||||
const registerPassword = ref('')
|
||||
const confirmPassword = ref('')
|
||||
const nameError = ref('')
|
||||
const registerEmailError = ref('')
|
||||
const registerPasswordError = ref('')
|
||||
const confirmPasswordError = ref('')
|
||||
|
||||
// Validation Methods - Login
|
||||
const validateEmail = () => {
|
||||
const emailRegex = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$|^[a-zA-Z0-9_.-]+$/
|
||||
@ -233,80 +118,15 @@ const validatePassword = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// Validation Methods - Register
|
||||
const validateName = () => {
|
||||
if (!name.value) {
|
||||
nameError.value = 'Nome é obrigatório'
|
||||
return false
|
||||
} else if (name.value.length < 3) {
|
||||
nameError.value = 'Nome deve ter pelo menos 3 caracteres'
|
||||
return false
|
||||
} else {
|
||||
nameError.value = ''
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const validateRegisterEmail = () => {
|
||||
const emailRegex = /^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/
|
||||
|
||||
if (!registerEmail.value) {
|
||||
registerEmailError.value = 'Email é obrigatório'
|
||||
return false
|
||||
} else if (!emailRegex.test(registerEmail.value)) {
|
||||
registerEmailError.value = 'Formato de email inválido'
|
||||
return false
|
||||
} else {
|
||||
registerEmailError.value = ''
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const validateRegisterPassword = () => {
|
||||
if (!registerPassword.value) {
|
||||
registerPasswordError.value = 'Senha é obrigatória'
|
||||
return false
|
||||
} else if (registerPassword.value.length < 6) {
|
||||
registerPasswordError.value = 'Senha deve ter pelo menos 6 caracteres'
|
||||
return false
|
||||
} else {
|
||||
registerPasswordError.value = ''
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
const validateConfirmPassword = () => {
|
||||
if (!confirmPassword.value) {
|
||||
confirmPasswordError.value = 'Confirme sua senha'
|
||||
return false
|
||||
} else if (confirmPassword.value !== registerPassword.value) {
|
||||
confirmPasswordError.value = 'As senhas não correspondem'
|
||||
return false
|
||||
} else {
|
||||
confirmPasswordError.value = ''
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Watch for changes to validate in real-time
|
||||
watch(email, () => { if (email.value) validateEmail() })
|
||||
watch(password, () => { if (password.value) validatePassword() })
|
||||
watch(name, () => { if (name.value) validateName() })
|
||||
watch(registerEmail, () => { if (registerEmail.value) validateRegisterEmail() })
|
||||
watch(registerPassword, () => { if (registerPassword.value) validateRegisterPassword() })
|
||||
watch(confirmPassword, () => { if (confirmPassword.value) validateConfirmPassword() })
|
||||
|
||||
// Form Validation
|
||||
const isLoginFormValid = computed(() => {
|
||||
return email.value && password.value && !emailError.value && !passwordError.value
|
||||
})
|
||||
|
||||
const isRegisterFormValid = computed(() => {
|
||||
return name.value && registerEmail.value && registerPassword.value &&
|
||||
confirmPassword.value && !nameError.value && !registerEmailError.value &&
|
||||
!registerPasswordError.value && !confirmPasswordError.value
|
||||
})
|
||||
|
||||
// Login Handlers
|
||||
const handleLogin = async () => {
|
||||
if (isLoginFormValid.value) {
|
||||
@ -329,29 +149,10 @@ const handleSSO = async () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const handleRegister = async () => {
|
||||
if (isRegisterFormValid.value) {
|
||||
try {
|
||||
await authStore.register(name.value, registerEmail.value, registerPassword.value)
|
||||
alert('Registro realizado com sucesso! Faça login para continuar.')
|
||||
|
||||
// Clear register form
|
||||
name.value = ''
|
||||
registerEmail.value = ''
|
||||
registerPassword.value = ''
|
||||
confirmPassword.value = ''
|
||||
|
||||
// Switch to login tab
|
||||
currentTab.value = 'login'
|
||||
} catch (error) {
|
||||
alert('Falha no registro. Por favor, tente novamente.')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Mantendo os estilos do login */
|
||||
.login-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -365,7 +166,7 @@ const handleRegister = async () => {
|
||||
|
||||
.login-wrapper {
|
||||
width: 70%;
|
||||
max-width: 600px; /* Reduzido para focar na área do formulário */
|
||||
max-width: 600px;
|
||||
background-color: white;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 20px;
|
||||
@ -383,11 +184,11 @@ const handleRegister = async () => {
|
||||
.logo-top {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 0rem;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.logo-image {
|
||||
max-width: 150px;
|
||||
max-width: 250px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
@ -395,99 +196,28 @@ const handleRegister = async () => {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.tab-buttons {
|
||||
display: flex;
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.tab-btn {
|
||||
flex: 1;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0.75rem;
|
||||
cursor: pointer;
|
||||
color: #6b7280;
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tab-btn.active {
|
||||
color: #36a8ca;
|
||||
border-bottom-color: #4cc9f0;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
text-align: light;
|
||||
text-align: flex;
|
||||
color: #2eaacf;
|
||||
margin-bottom: 0px; /* Aumente esse valor se precisar de mais espaço entre o título e o subtítulo */
|
||||
font-size: 20px;
|
||||
text-transform: capitalize;
|
||||
font-size: 23px;
|
||||
}
|
||||
|
||||
.login-sub-title {
|
||||
text-align: light;
|
||||
text-align: flex;
|
||||
color: #2eaacf;
|
||||
margin-top: 0; /* Pode ajustar se quiser controlar o espaçamento entre título e subtítulo */
|
||||
margin-bottom: 20px; /* Ajuste esse valor conforme necessário */
|
||||
font-size: 15px;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.register-title {
|
||||
text-align: light;
|
||||
color: #2eaacf;
|
||||
margin-bottom: 0px; /* Aumente esse valor se precisar de mais espaço entre o título e o subtítulo */
|
||||
font-size: 20px;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.register-sub-title {
|
||||
text-align: light;
|
||||
color: #2eaacf;
|
||||
margin-top: 0; /* Pode ajustar se quiser controlar o espaçamento entre título e subtítulo */
|
||||
margin-bottom: 20px; /* Ajuste esse valor conforme necessário */
|
||||
font-size: 15px;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Estilos para campos de senha lado a lado */
|
||||
.password-row {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.password-field {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #4cc9f0;
|
||||
}
|
||||
|
||||
.form-group input {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 25px;
|
||||
outline: none;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.form-group input:focus {
|
||||
border-color: #4cc9f0;
|
||||
}
|
||||
|
||||
.input-error {
|
||||
@ -497,40 +227,27 @@ const handleRegister = async () => {
|
||||
.error-message {
|
||||
color: red;
|
||||
font-size: 0.8rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 0.75rem;
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s, transform 0.1s;
|
||||
}
|
||||
|
||||
.btn:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn:active:not(:disabled) {
|
||||
transform: translateY(1px);
|
||||
margin-top: 0rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
padding: 3px;
|
||||
background-color: #4cc9f0;
|
||||
color: white;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
padding: 3px;
|
||||
background-color: #f8f9fa;
|
||||
color: #4cc9f0;
|
||||
border-radius: 10px;
|
||||
border: 1px solid #4cc9f0;
|
||||
}
|
||||
|
||||
@ -538,25 +255,4 @@ const handleRegister = async () => {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.login-wrapper {
|
||||
flex-direction: column;
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.logo-section {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.logo-image {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
/* Ajuste responsivo para campos de senha em telas pequenas */
|
||||
.password-row {
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue
Block a user