From e19798e5823c9f97621587ce2a0ab1434bf5486c Mon Sep 17 00:00:00 2001 From: JuruSysadmin Date: Thu, 15 Jan 2026 15:25:31 -0300 Subject: [PATCH 1/2] =?UTF-8?q?refactor(profile):=20aplicar=20DDD=20com=20?= =?UTF-8?q?Intent-Revealing=20Names=20e=20Linguagem=20Ub=C3=ADqua?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Renomear métodos e propriedades para português (Linguagem Ubíqua) - Aplicar Intent-Revealing Names na entidade Colaborador - Corrigir mapToSafeProfile para suportar nomes da entidade DDD - Remover comentários redundantes (nomes auto-explicativos) Arquivos modificados: - Colaborador.ts: fromDto → criarAPartirDoDto, ehRCA → ehRepresentanteComercial - profile.service.ts: getMe → obterColaboradorAtual - ProfilePage.tsx: atualizar referências aos novos nomes - mappers.ts: suportar ambos formatos (entidade e DTO) --- .../login/components/AuthInitializer.tsx | 2 +- src/features/login/hooks/useAuth.ts | 4 +- src/features/login/interfaces/types.ts | 6 +- src/features/login/utils/mappers.ts | 20 +++-- .../profile/components/ProfilePage.tsx | 79 +++++++++++++++---- src/features/profile/domain/Colaborador.ts | 71 +++++++++++++++++ src/features/profile/index.ts | 3 +- .../profile/services/profile.service.ts | 20 ++++- src/features/profile/types.ts | 2 +- 9 files changed, 174 insertions(+), 33 deletions(-) create mode 100644 src/features/profile/domain/Colaborador.ts diff --git a/src/features/login/components/AuthInitializer.tsx b/src/features/login/components/AuthInitializer.tsx index 93dcfd6..4df399f 100644 --- a/src/features/login/components/AuthInitializer.tsx +++ b/src/features/login/components/AuthInitializer.tsx @@ -20,7 +20,7 @@ export function AuthInitializer({ children }: { children: React.ReactNode }) { try { await loginService.refreshToken(); - const profile = await profileService.getMe(); + const profile = await profileService.obterColaboradorAtual(); setUser(mapToSafeProfile(profile)); } catch (error) { console.warn('Sessão expirada ou inválida', error); diff --git a/src/features/login/hooks/useAuth.ts b/src/features/login/hooks/useAuth.ts index 94c9032..07f38ab 100644 --- a/src/features/login/hooks/useAuth.ts +++ b/src/features/login/hooks/useAuth.ts @@ -16,7 +16,7 @@ export function useAuth() { mutationFn: loginService.login, onSuccess: async () => { try { - const profile = await profileService.getMe(); + const profile = await profileService.obterColaboradorAtual(); const safeProfile = mapToSafeProfile(profile); setUser(safeProfile); @@ -34,7 +34,7 @@ export function useAuth() { useQuery({ queryKey: ['auth-me'], queryFn: async () => { - const data = await profileService.getMe(); + const data = await profileService.obterColaboradorAtual(); const safeData = mapToSafeProfile(data); setUser(safeData); return safeData; diff --git a/src/features/login/interfaces/types.ts b/src/features/login/interfaces/types.ts index a6178bd..bd6f67e 100644 --- a/src/features/login/interfaces/types.ts +++ b/src/features/login/interfaces/types.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; import type { ReactNode } from 'react'; -import type { UserProfile } from '../../profile/types'; +import type { UserProfileDto } from '../../profile/types'; import { loginSchema, @@ -38,9 +38,9 @@ export interface AuthLoginProps { } export interface AuthState { - user: UserProfile | null; + user: UserProfileDto | null; isAuthenticated: boolean; - setUser: (user: UserProfile | null) => void; + setUser: (user: UserProfileDto | null) => void; logout: () => void; hydrate: () => void; } diff --git a/src/features/login/utils/mappers.ts b/src/features/login/utils/mappers.ts index e130a0d..d1c2013 100644 --- a/src/features/login/utils/mappers.ts +++ b/src/features/login/utils/mappers.ts @@ -1,16 +1,22 @@ -import { UserProfile } from '../../profile/types'; +import { UserProfileDto } from '../../profile/types'; +import { Colaborador } from '../../profile/domain/Colaborador'; -export const mapToSafeProfile = (data: any): UserProfile => { +/** + * Converte Colaborador (entidade) ou objeto raw para UserProfileDto. + * Suporta ambos os formatos de propriedade (entidade DDD e DTO da API). + */ +export const mapToSafeProfile = (data: Colaborador | any): UserProfileDto => { return { matricula: data.matricula, userName: data.userName, nome: data.nome, codigoFilial: data.codigoFilial, nomeFilial: data.nomeFilial, - rca: data.rca, - discountPercent: data.discountPercent, - sectorId: data.sectorId, - sectorManagerId: data.sectorManagerId, - supervisorId: data.supervisorId, + rca: data.codigoRCA ?? data.rca, + discountPercent: data.percentualDesconto ?? data._percentualDesconto ?? data.discountPercent, + sectorId: data.codigoSetor ?? data.sectorId, + sectorManagerId: data.sectorManagerId ?? 0, + supervisorId: data.codigoSupervisor ?? data.supervisorId, }; }; + diff --git a/src/features/profile/components/ProfilePage.tsx b/src/features/profile/components/ProfilePage.tsx index b8061c5..b1a9b89 100644 --- a/src/features/profile/components/ProfilePage.tsx +++ b/src/features/profile/components/ProfilePage.tsx @@ -7,15 +7,23 @@ import Card from '@mui/material/Card'; import CardContent from '@mui/material/CardContent'; import CircularProgress from '@mui/material/CircularProgress'; import Alert from '@mui/material/Alert'; +import Avatar from '@mui/material/Avatar'; +import Chip from '@mui/material/Chip'; import { useAuthStore } from '../../login/store/useAuthStore'; import { useAuth } from '../../login/hooks/useAuth'; +import { Colaborador } from '../domain/Colaborador'; export default function ProfilePage() { const { useMe } = useAuth(); - const { data: profile, isLoading, error } = useMe(); + const { data: colaborador, isLoading, error } = useMe(); const user = useAuthStore((s) => s.user); - const displayData = profile || user; + // Converte o DTO para a entidade de domínio Colaborador + const displayData: Colaborador | null = colaborador + ? Colaborador.criarAPartirDoDto(colaborador) + : user + ? Colaborador.criarAPartirDoDto(user) + : null; if (isLoading) { return ( @@ -42,6 +50,47 @@ export default function ProfilePage() { return ( + {/* Header com Avatar e Nome */} + + + + + + {displayData.iniciais} + + + + {displayData.nome} + + + {displayData.nomeComFilial} + + + {displayData.ehRepresentanteComercial && ( + + )} + {displayData.podeAplicarDesconto && ( + + )} + + + + + + + + {/* Informações Pessoais */} @@ -78,6 +127,7 @@ export default function ProfilePage() { + {/* Informações Profissionais */} @@ -90,8 +140,7 @@ export default function ProfilePage() { Filial - {displayData.nomeFilial || '-'} ( - {displayData.codigoFilial || '-'}) + {displayData.nomeFilial || '-'} ({displayData.codigoFilial || '-'}) @@ -99,16 +148,16 @@ export default function ProfilePage() { RCA - {displayData.rca || '-'} + {displayData.ehRepresentanteComercial ? displayData.codigoRCA : 'Não é vendedor'} - {displayData.discountPercent !== undefined && ( + {displayData.podeAplicarDesconto && ( - Desconto (%) + Desconto Disponível - {displayData.discountPercent}% + {displayData.percentualDesconto}% )} @@ -117,9 +166,9 @@ export default function ProfilePage() { - {(displayData.sectorId !== undefined || - displayData.sectorManagerId !== undefined || - displayData.supervisorId !== undefined) && ( + {/* Informações Adicionais */} + {(displayData.codigoSetor !== undefined || + displayData.codigoSupervisor !== undefined) && ( @@ -127,23 +176,23 @@ export default function ProfilePage() { Informações Adicionais - {displayData.sectorId !== undefined && ( + {displayData.codigoSetor !== undefined && ( Setor - {displayData.sectorId} + {displayData.codigoSetor} )} - {displayData.supervisorId !== undefined && ( + {displayData.codigoSupervisor !== undefined && ( Supervisor - {displayData.supervisorId} + {displayData.codigoSupervisor} )} diff --git a/src/features/profile/domain/Colaborador.ts b/src/features/profile/domain/Colaborador.ts new file mode 100644 index 0000000..0de80b3 --- /dev/null +++ b/src/features/profile/domain/Colaborador.ts @@ -0,0 +1,71 @@ +import { UserProfileDto } from '../types'; + +/** + * Entidade de Domínio: Colaborador + */ +export class Colaborador { + private constructor( + public readonly matricula: number, + public readonly userName: string, + public readonly nome: string, + public readonly codigoFilial: string, + public readonly nomeFilial: string, + public readonly codigoRCA: number, + private readonly _percentualDesconto: number, + public readonly codigoSetor: number, + public readonly codigoSupervisor: number + ) {} + + // ========== FACTORY METHODS ========== + + static criarAPartirDoDto(dto: UserProfileDto): Colaborador { + return new Colaborador( + dto.matricula, + dto.userName, + dto.nome, + dto.codigoFilial, + dto.nomeFilial, + dto.rca, + dto.discountPercent, + dto.sectorId, + dto.supervisorId + ); + } + + // ========== COMPUTED PROPERTIES ========== + + get iniciais(): string { + if (!this.nome) return 'U'; + const partes = this.nome.trim().split(' ').filter(Boolean); + if (partes.length === 1) { + return partes[0][0].toUpperCase(); + } + return (partes[0][0] + partes[partes.length - 1][0]).toUpperCase(); + } + + get ehRepresentanteComercial(): boolean { + return this.codigoRCA > 0; + } + + get podeAplicarDesconto(): boolean { + return this._percentualDesconto > 0 && this.ehRepresentanteComercial; + } + + get percentualDesconto(): number { + return this._percentualDesconto; + } + + get nomeComFilial(): string { + return `${this.nome} - ${this.nomeFilial}`; + } + + // ========== BUSINESS METHODS ========== + + aplicarDescontoAoValor(valorOriginal: number): number { + if (!this.podeAplicarDesconto) { + return valorOriginal; + } + return valorOriginal * (1 - this._percentualDesconto / 100); + } +} + diff --git a/src/features/profile/index.ts b/src/features/profile/index.ts index d580e7e..eaf7d14 100644 --- a/src/features/profile/index.ts +++ b/src/features/profile/index.ts @@ -1,3 +1,4 @@ // Profile feature barrel export export { default as ProfilePage } from './components/ProfilePage'; -export type { UserProfile } from './types'; +export type { UserProfileDto } from './types'; +export { Colaborador } from './domain/Colaborador'; diff --git a/src/features/profile/services/profile.service.ts b/src/features/profile/services/profile.service.ts index 57f9576..d0924aa 100644 --- a/src/features/profile/services/profile.service.ts +++ b/src/features/profile/services/profile.service.ts @@ -1,9 +1,23 @@ import { profileApi } from '../api'; -import { UserProfile } from '../types'; +import { UserProfileDto } from '../types'; +import { Colaborador } from '../domain/Colaborador'; export const profileService = { - getMe: async (): Promise => { - const response = await profileApi.get('/auth/me'); + /** + * Obtém o colaborador atualmente autenticado como entidade de domínio. + * Segue o padrão de Linguagem Ubíqua do DDD. + */ + obterColaboradorAtual: async (): Promise => { + const response = await profileApi.get('/auth/me'); + return Colaborador.criarAPartirDoDto(response.data); + }, + + /** + * Obtém os dados brutos (DTO) do colaborador autenticado. + * Usar apenas quando a conversão para entidade de domínio não for necessária. + */ + obterColaboradorAtualDto: async (): Promise => { + const response = await profileApi.get('/auth/me'); return response.data; }, }; diff --git a/src/features/profile/types.ts b/src/features/profile/types.ts index 07a5876..27e17ba 100644 --- a/src/features/profile/types.ts +++ b/src/features/profile/types.ts @@ -1,7 +1,7 @@ /** * Tipagem da resposta do User Info (Endpoint 1.3) */ -export interface UserProfile { +export interface UserProfileDto { matricula: number; userName: string; nome: string; From c66bc9620bf7b33bc7534f1568d0537a45d82053 Mon Sep 17 00:00:00 2001 From: JuruSysadmin Date: Thu, 15 Jan 2026 15:49:23 -0300 Subject: [PATCH 2/2] feat: Implement user authentication initialization and profile management with a Colaborador domain entity. --- src/features/dashboard/header/AppLinks.tsx | 64 ------ src/features/dashboard/header/Header.tsx | 15 +- .../dashboard/header/MobileRightSidebar.tsx | 128 ------------ src/features/dashboard/header/Navigation.tsx | 135 ------------- .../dashboard/header/Notification.tsx | 132 ------------- src/features/dashboard/header/Profile.tsx | 74 ++++--- src/features/dashboard/header/data.ts | 185 ------------------ src/features/login/hooks/useAuth.ts | 20 +- .../profile/components/ProfilePage.tsx | 56 +++--- .../profile/hooks/useColaboradorAtual.ts | 19 ++ src/features/profile/index.ts | 1 + 11 files changed, 93 insertions(+), 736 deletions(-) delete mode 100644 src/features/dashboard/header/AppLinks.tsx delete mode 100644 src/features/dashboard/header/MobileRightSidebar.tsx delete mode 100644 src/features/dashboard/header/Navigation.tsx delete mode 100644 src/features/dashboard/header/Notification.tsx delete mode 100644 src/features/dashboard/header/data.ts create mode 100644 src/features/profile/hooks/useColaboradorAtual.ts diff --git a/src/features/dashboard/header/AppLinks.tsx b/src/features/dashboard/header/AppLinks.tsx deleted file mode 100644 index 80f8e8f..0000000 --- a/src/features/dashboard/header/AppLinks.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { Avatar, Box, Typography, Grid, Stack } from '@mui/material'; -import * as dropdownData from './data'; -import Link from 'next/link'; -import React from 'react'; - -const AppLinks = () => { - return ( - - {dropdownData.appsLink.map((links) => ( - - - - - - - - - {links.title} - - - {links.subtext} - - - - - - ))} - - ); -}; - -export default AppLinks; diff --git a/src/features/dashboard/header/Header.tsx b/src/features/dashboard/header/Header.tsx index 1857583..16cee51 100644 --- a/src/features/dashboard/header/Header.tsx +++ b/src/features/dashboard/header/Header.tsx @@ -12,11 +12,8 @@ import DarkModeIcon from '@mui/icons-material/DarkMode'; import LightModeIcon from '@mui/icons-material/LightMode'; import { useCustomizerStore } from '../store/useCustomizerStore'; -import Notifications from './Notification'; import Profile from './Profile'; import Search from './Search'; -import Navigation from './Navigation'; -import MobileRightSidebar from './MobileRightSidebar'; const AppBarStyled = styled(AppBar)(({ theme }) => ({ boxShadow: 'none', @@ -33,7 +30,6 @@ const ToolbarStyled = styled(Toolbar)(({ theme }) => ({ const Header = () => { const lgUp = useMediaQuery((theme: Theme) => theme.breakpoints.up('lg')); - const lgDown = useMediaQuery((theme: Theme) => theme.breakpoints.down('lg')); const { activeMode, @@ -51,7 +47,7 @@ const Header = () => { {/* ------------------------------------------- */} - {/* Toggle Button Sidebar (Fluxo 2) */} + {/* Toggle Button Sidebar */} {/* ------------------------------------------- */} { {/* ------------------------------------------- */} - {/* Search & Navigation */} + {/* Search */} {/* ------------------------------------------- */} - {lgUp && } @@ -84,12 +79,9 @@ const Header = () => { {activeMode === 'light' ? : } - - {/* ------------------------------------------- */} - {/* Mobile Right Sidebar & Profile */} + {/* Profile */} {/* ------------------------------------------- */} - {lgDown && } @@ -98,3 +90,4 @@ const Header = () => { }; export default Header; + diff --git a/src/features/dashboard/header/MobileRightSidebar.tsx b/src/features/dashboard/header/MobileRightSidebar.tsx deleted file mode 100644 index b165d4a..0000000 --- a/src/features/dashboard/header/MobileRightSidebar.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import React, { useState } from 'react'; -import { - IconApps, - IconChevronDown, - IconChevronUp, - IconGridDots, - IconMail, - IconMessages, -} from '@tabler/icons-react'; -import { - Box, - Typography, - Drawer, - IconButton, - List, - ListItemButton, - ListItemIcon, - ListItemText, - Collapse, -} from '@mui/material'; - -import Link from 'next/link'; -import AppLinks from './AppLinks'; - -const MobileRightSidebar = () => { - const [showDrawer, setShowDrawer] = useState(false); - - const [open, setOpen] = React.useState(true); - - const handleClick = () => { - setOpen(!open); - }; - - const cartContent = ( - - {/* ------------------------------------------- */} - {/* Apps Content */} - {/* ------------------------------------------- */} - - - - - - - - - Chats - - - - - - - - - - Email - - - - - - - - - - Apps - - - {open ? ( - - ) : ( - - )} - - - - - - - - - - - - ); - - return ( - - setShowDrawer(true)} - sx={{ - ...(showDrawer && { - color: 'primary.main', - }), - }} - > - - - {/* ------------------------------------------- */} - {/* Cart Sidebar */} - {/* ------------------------------------------- */} - setShowDrawer(false)} - PaperProps={{ sx: { width: '300px' } }} - > - - - Navigation - - - - {/* component */} - {cartContent} - - - ); -}; - -export default MobileRightSidebar; diff --git a/src/features/dashboard/header/Navigation.tsx b/src/features/dashboard/header/Navigation.tsx deleted file mode 100644 index e371d42..0000000 --- a/src/features/dashboard/header/Navigation.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { useState } from 'react'; -import { Box, Menu, Typography, Button, Divider, Grid } from '@mui/material'; -import Link from 'next/link'; -import { IconChevronDown, IconHelp } from '@tabler/icons-react'; -import AppLinks from './AppLinks'; - -const AppDD = () => { - const [anchorEl2, setAnchorEl2] = useState(null); - - const handleClick2 = (event: any) => { - setAnchorEl2(event.currentTarget); - }; - - const handleClose2 = () => { - setAnchorEl2(null); - }; - - return ( - <> - - - {/* ------------------------------------------- */} - {/* Message Dropdown */} - {/* ------------------------------------------- */} - - - - - - - - - - - Frequently Asked Questions - - - - - - - - - - - - - - - - - ); -}; - -export default AppDD; diff --git a/src/features/dashboard/header/Notification.tsx b/src/features/dashboard/header/Notification.tsx deleted file mode 100644 index 89d49e1..0000000 --- a/src/features/dashboard/header/Notification.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React, { useState } from 'react'; -import { - IconButton, - Box, - Badge, - Menu, - MenuItem, - Avatar, - Typography, - Button, - Chip, -} from '@mui/material'; -import * as dropdownData from './data'; -import { Scrollbar } from '@/shared/components'; - -import { IconBellRinging } from '@tabler/icons-react'; -import { Stack } from '@mui/system'; -import Link from 'next/link'; - -const Notifications = () => { - const [anchorEl2, setAnchorEl2] = useState(null); - - const handleClick2 = (event: any) => { - setAnchorEl2(event.currentTarget); - }; - - const handleClose2 = () => { - setAnchorEl2(null); - }; - - return ( - - - - - - - {/* ------------------------------------------- */} - {/* Message Dropdown */} - {/* ------------------------------------------- */} - - - Notifications - - - - {dropdownData.notifications.map((notification) => ( - - - - - - - {notification.title} - - - {notification.subtitle} - - - - - - ))} - - - - - - - ); -}; - -export default Notifications; diff --git a/src/features/dashboard/header/Profile.tsx b/src/features/dashboard/header/Profile.tsx index b8f4aee..0d8394d 100644 --- a/src/features/dashboard/header/Profile.tsx +++ b/src/features/dashboard/header/Profile.tsx @@ -5,11 +5,9 @@ import { Menu, Avatar, Typography, - Divider, Button, IconButton, } from '@mui/material'; -import { IconMail } from '@tabler/icons-react'; import { Stack } from '@mui/system'; import { useAuthStore } from '../../login/store/useAuthStore'; @@ -27,10 +25,18 @@ const Profile = () => { setAnchorEl2(null); }; + // Gera as iniciais do nome + const getIniciais = () => { + if (!user?.nome) return user?.userName?.[0]?.toUpperCase() || 'U'; + const partes = user.nome.trim().split(' ').filter(Boolean); + if (partes.length === 1) return partes[0][0].toUpperCase(); + return (partes[0][0] + partes[partes.length - 1][0]).toUpperCase(); + }; + return ( { bgcolor: 'primary.main', }} > - {user?.nome?.[0] || user?.userName?.[0] || 'U'} + {getIniciais()} {/* ------------------------------------------- */} - {/* Message Dropdown */} + {/* Profile Dropdown */} {/* ------------------------------------------- */} { transformOrigin={{ horizontal: 'right', vertical: 'top' }} sx={{ '& .MuiMenu-paper': { - width: '360px', - p: 4, + width: '320px', + p: 3, }, }} > - User Profile - + + Meu Perfil + + - {user?.nome?.[0] || user?.userName?.[0] || 'U'} + {getIniciais()} { > {user?.nome || user?.userName || 'Usuário'} - - {user?.nomeFilial || 'Sem filial'} + + {user?.nomeFilial || '-'} - - - {user?.rca ? `RCA: ${user.rca}` : 'Sem e-mail'} + + Matrícula: {user?.matricula || '-'} - - - + + ); }; export default Profile; + diff --git a/src/features/dashboard/header/data.ts b/src/features/dashboard/header/data.ts deleted file mode 100644 index 8383eb9..0000000 --- a/src/features/dashboard/header/data.ts +++ /dev/null @@ -1,185 +0,0 @@ -// Notifications dropdown - -interface NotificationType { - id: string; - avatar: string; - title: string; - subtitle: string; -} - -const notifications: NotificationType[] = [ - { - id: '1', - avatar: '/images/profile/user-2.jpg', - title: 'Roman Joined the Team!', - subtitle: 'Congratulate him', - }, - { - id: '2', - avatar: '/images/profile/user-3.jpg', - title: 'New message received', - subtitle: 'Salma sent you new message', - }, - { - id: '3', - avatar: '/images/profile/user-4.jpg', - title: 'New Payment received', - subtitle: 'Check your earnings', - }, - { - id: '4', - avatar: '/images/profile/user-5.jpg', - title: 'Jolly completed tasks', - subtitle: 'Assign her new tasks', - }, - { - id: '5', - avatar: '/images/profile/user-6.jpg', - title: 'Roman Joined the Team!', - subtitle: 'Congratulate him', - }, - { - id: '6', - avatar: '/images/profile/user-7.jpg', - title: 'New message received', - subtitle: 'Salma sent you new message', - }, - { - id: '7', - avatar: '/images/profile/user-8.jpg', - title: 'New Payment received', - subtitle: 'Check your earnings', - }, - { - id: '8', - avatar: '/images/profile/user-9.jpg', - title: 'Jolly completed tasks', - subtitle: 'Assign her new tasks', - }, -]; - -// -// Profile dropdown -// -interface ProfileType { - href: string; - title: string; - subtitle: string; - icon: any; -} -const profile: ProfileType[] = [ - { - href: '/dashboard/profile', - title: 'My Profile', - subtitle: 'Account Settings', - icon: '/images/svgs/icon-account.svg', - }, - { - href: '/apps/email', - title: 'My Inbox', - subtitle: 'Messages & Emails', - icon: '/images/svgs/icon-inbox.svg', - }, - { - href: '/apps/notes', - title: 'My Tasks', - subtitle: 'To-do and Daily Tasks', - icon: '/images/svgs/icon-tasks.svg', - }, -]; - -// apps dropdown - -interface AppsLinkType { - href: string; - title: string; - subtext: string; - avatar: string; -} - -const appsLink: AppsLinkType[] = [ - { - href: '/apps/chats', - title: 'Chat Application', - subtext: 'New messages arrived', - avatar: '/images/svgs/icon-dd-chat.svg', - }, - { - href: '/apps/ecommerce/shop', - title: 'eCommerce App', - subtext: 'New stock available', - avatar: '/images/svgs/icon-dd-cart.svg', - }, - { - href: '/apps/notes', - title: 'Notes App', - subtext: 'To-do and Daily tasks', - avatar: '/images/svgs/icon-dd-invoice.svg', - }, - { - href: '/apps/contacts', - title: 'Contact Application', - subtext: '2 Unsaved Contacts', - avatar: '/images/svgs/icon-dd-mobile.svg', - }, - { - href: '/apps/tickets', - title: 'Tickets App', - subtext: 'Submit tickets', - avatar: '/images/svgs/icon-dd-lifebuoy.svg', - }, - { - href: '/apps/email', - title: 'Email App', - subtext: 'Get new emails', - avatar: '/images/svgs/icon-dd-message-box.svg', - }, - { - href: '/apps/blog/post', - title: 'Blog App', - subtext: 'added new blog', - avatar: '/images/svgs/icon-dd-application.svg', - }, -]; - -interface LinkType { - href: string; - title: string; -} - -const pageLinks: LinkType[] = [ - { - href: '/theme-pages/pricing', - title: 'Pricing Page', - }, - { - href: '/auth/auth1/login', - title: 'Authentication Design', - }, - { - href: '/auth/auth1/register', - title: 'Register Now', - }, - { - href: '/404', - title: '404 Error Page', - }, - { - href: '/apps/note', - title: 'Notes App', - }, - { - href: '/apps/user-profile/profile', - title: 'User Application', - }, - { - href: '/apps/blog/post', - title: 'Blog Design', - }, - { - href: '/apps/ecommerce/checkout', - title: 'Shopping Cart', - }, -]; - -export { notifications, profile, pageLinks, appsLink }; diff --git a/src/features/login/hooks/useAuth.ts b/src/features/login/hooks/useAuth.ts index 07f38ab..6c2a213 100644 --- a/src/features/login/hooks/useAuth.ts +++ b/src/features/login/hooks/useAuth.ts @@ -1,10 +1,11 @@ -import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useRouter } from 'next/navigation'; import { useAuthStore } from '../store/useAuthStore'; import { loginService } from '../services/login.service'; import { profileService } from '../../profile/services/profile.service'; import { clearAuthData } from '../utils/tokenRefresh'; import { mapToSafeProfile } from '../utils/mappers'; +import { COLABORADOR_ATUAL_QUERY_KEY } from '../../profile'; export function useAuth() { const queryClient = useQueryClient(); @@ -20,7 +21,7 @@ export function useAuth() { const safeProfile = mapToSafeProfile(profile); setUser(safeProfile); - queryClient.setQueryData(['auth-me'], safeProfile); + queryClient.setQueryData(COLABORADOR_ATUAL_QUERY_KEY, profile); router.push('/dashboard'); } catch (error) { @@ -30,19 +31,6 @@ export function useAuth() { }, }); - const useMe = () => - useQuery({ - queryKey: ['auth-me'], - queryFn: async () => { - const data = await profileService.obterColaboradorAtual(); - const safeData = mapToSafeProfile(data); - setUser(safeData); - return safeData; - }, - retry: false, - staleTime: Infinity, - }); - const logout = async () => { try { await loginService.logout(); @@ -54,5 +42,5 @@ export function useAuth() { } }; - return { loginMutation, useMe, logout }; + return { loginMutation, logout }; } diff --git a/src/features/profile/components/ProfilePage.tsx b/src/features/profile/components/ProfilePage.tsx index b1a9b89..507cc2c 100644 --- a/src/features/profile/components/ProfilePage.tsx +++ b/src/features/profile/components/ProfilePage.tsx @@ -9,21 +9,10 @@ import CircularProgress from '@mui/material/CircularProgress'; import Alert from '@mui/material/Alert'; import Avatar from '@mui/material/Avatar'; import Chip from '@mui/material/Chip'; -import { useAuthStore } from '../../login/store/useAuthStore'; -import { useAuth } from '../../login/hooks/useAuth'; -import { Colaborador } from '../domain/Colaborador'; +import { useColaboradorAtual } from '../hooks/useColaboradorAtual'; export default function ProfilePage() { - const { useMe } = useAuth(); - const { data: colaborador, isLoading, error } = useMe(); - const user = useAuthStore((s) => s.user); - - // Converte o DTO para a entidade de domínio Colaborador - const displayData: Colaborador | null = colaborador - ? Colaborador.criarAPartirDoDto(colaborador) - : user - ? Colaborador.criarAPartirDoDto(user) - : null; + const { data: colaborador, isLoading, error } = useColaboradorAtual(); if (isLoading) { return ( @@ -44,7 +33,7 @@ export default function ProfilePage() { return Erro ao carregar dados do perfil; } - if (!displayData) { + if (!colaborador) { return Nenhum dado de perfil disponível; } @@ -63,22 +52,22 @@ export default function ProfilePage() { fontSize: '1.5rem', }} > - {displayData.iniciais} + {colaborador.iniciais} - {displayData.nome} + {colaborador.nome} - {displayData.nomeComFilial} + {colaborador.nomeComFilial} - {displayData.ehRepresentanteComercial && ( + {colaborador.ehRepresentanteComercial && ( )} - {displayData.podeAplicarDesconto && ( + {colaborador.podeAplicarDesconto && ( @@ -103,7 +92,7 @@ export default function ProfilePage() { Nome - {displayData.nome || '-'} + {colaborador.nome || '-'} @@ -111,7 +100,7 @@ export default function ProfilePage() { Usuário - {displayData.userName || '-'} + {colaborador.userName || '-'} @@ -119,7 +108,7 @@ export default function ProfilePage() { Matrícula - {displayData.matricula || '-'} + {colaborador.matricula || '-'} @@ -140,7 +129,7 @@ export default function ProfilePage() { Filial - {displayData.nomeFilial || '-'} ({displayData.codigoFilial || '-'}) + {colaborador.nomeFilial || '-'} ({colaborador.codigoFilial || '-'}) @@ -148,16 +137,16 @@ export default function ProfilePage() { RCA - {displayData.ehRepresentanteComercial ? displayData.codigoRCA : 'Não é vendedor'} + {colaborador.ehRepresentanteComercial ? colaborador.codigoRCA : 'Não é vendedor'} - {displayData.podeAplicarDesconto && ( + {colaborador.podeAplicarDesconto && ( Desconto Disponível - {displayData.percentualDesconto}% + {colaborador.percentualDesconto}% )} @@ -167,8 +156,8 @@ export default function ProfilePage() { {/* Informações Adicionais */} - {(displayData.codigoSetor !== undefined || - displayData.codigoSupervisor !== undefined) && ( + {(colaborador.codigoSetor !== undefined || + colaborador.codigoSupervisor !== undefined) && ( @@ -176,23 +165,23 @@ export default function ProfilePage() { Informações Adicionais - {displayData.codigoSetor !== undefined && ( + {colaborador.codigoSetor !== undefined && ( Setor - {displayData.codigoSetor} + {colaborador.codigoSetor} )} - {displayData.codigoSupervisor !== undefined && ( + {colaborador.codigoSupervisor !== undefined && ( Supervisor - {displayData.codigoSupervisor} + {colaborador.codigoSupervisor} )} @@ -204,3 +193,4 @@ export default function ProfilePage() { ); } + diff --git a/src/features/profile/hooks/useColaboradorAtual.ts b/src/features/profile/hooks/useColaboradorAtual.ts new file mode 100644 index 0000000..c5d940a --- /dev/null +++ b/src/features/profile/hooks/useColaboradorAtual.ts @@ -0,0 +1,19 @@ +import { useQuery, UseQueryResult } from '@tanstack/react-query'; +import { profileService } from '../services/profile.service'; +import { Colaborador } from '../domain/Colaborador'; + +export const COLABORADOR_ATUAL_QUERY_KEY = ['colaborador-atual'] as const; + +/** + * Hook para obter o colaborador atualmente autenticado. + * Encapsula a lógica de busca e cache do perfil do usuário, + * desacoplando essa responsabilidade do módulo de login. + */ +export function useColaboradorAtual(): UseQueryResult { + return useQuery({ + queryKey: COLABORADOR_ATUAL_QUERY_KEY, + queryFn: () => profileService.obterColaboradorAtual(), + retry: false, + staleTime: Infinity, + }); +} diff --git a/src/features/profile/index.ts b/src/features/profile/index.ts index eaf7d14..59bdeb7 100644 --- a/src/features/profile/index.ts +++ b/src/features/profile/index.ts @@ -2,3 +2,4 @@ export { default as ProfilePage } from './components/ProfilePage'; export type { UserProfileDto } from './types'; export { Colaborador } from './domain/Colaborador'; +export { useColaboradorAtual, COLABORADOR_ATUAL_QUERY_KEY } from './hooks/useColaboradorAtual';