Skip to content

feat: pagina de Perfil do usuario com preferencias (idioma, tema, senha) - #18

Merged
janeiaraujo merged 1 commit into
mainfrom
feat/user-profile-preferences
Aug 3, 2026
Merged

feat: pagina de Perfil do usuario com preferencias (idioma, tema, senha)#18
janeiaraujo merged 1 commit into
mainfrom
feat/user-profile-preferences

Conversation

@janeiaraujo

Copy link
Copy Markdown
Owner

O que resolve

Não existia tela de perfil no app. O link do usuário no rodapé da sidebar levava para Configurações, que é configuração da organização (tags, categorias, permissões), não da pessoa. E no backend só havia rotas de gestão de usuários restritas a admin/owner — ou seja, um membro comum não conseguia nem trocar a própria senha.

Também dá um lugar definitivo para a escolha de idioma: antes ela vivia só no localStorage do navegador e não acompanhava a conta.

Backend — rotas de auto-serviço

Rota O que faz
GET /api/users/me Perfil do próprio usuário
PATCH /api/users/me Nome + preferências (idioma, tema), com validação dos valores aceitos
POST /api/users/me/password Troca de senha exigindo a senha atual — diferente do PATCH /:userId de admin, que redefine direto

login, magic link e /auth/me agora devolvem preferences, para o frontend aplicar idioma/tema já na autenticação.

Frontend — nova página /profile

  • Identidade: avatar, papel, membro desde, último acesso
  • Dados pessoais: nome editável; e-mail somente leitura (não há fluxo de verificação de troca de e-mail hoje — melhor não fingir que há)
  • Preferências: idioma (PT/EN) e tema (claro/escuro/sistema), agora salvos na conta. Aplica na hora e reverte se o save falhar
  • Segurança: troca de senha

A sidebar passa a apontar para /profile. Todos os textos em pt.json/en.json.

Sobre "a opção de idioma não está aparecendo"

Investiguei: não é bug. O seletor PT/EN está no navbar desde o PR #17, que foi mesclado às 16:53. Sua aplicação estava rodando código anterior a esse merge.

Confirmei renderizando o navbar isoladamente no navegador (tema claro e escuro) — o botão aparece normalmente, em azul, entre o sino de notificações e o "Captura Rápida". Para vê-lo:

git pull
cd frontend && npm install && npm run dev

O npm install importa aqui porque o PR #17 adicionou dependências novas (react-i18next e afins).

Test plan

  • npm run build sem erros
  • Navbar renderizado isoladamente: botão PT/EN visível em ambos os temas
  • Com backend rodando: abrir /profile, trocar idioma, recarregar e confirmar que persistiu
  • Trocar a senha e re-logar com a nova
  • Testar com usuário member (não-admin) para confirmar o auto-serviço

Nao existia tela de perfil: o link do usuario na sidebar levava para
Configuracoes (que e configuracao da organizacao, nao da pessoa), e o
backend so tinha rotas de gestao de usuarios restritas a admin/owner -
um membro comum nao conseguia nem trocar a propria senha.

Backend - rotas de auto-servico em /api/users/me:
- GET    /me           perfil do proprio usuario
- PATCH  /me           nome + preferencias (idioma, tema), com validacao
- POST   /me/password  troca de senha exigindo a senha atual (diferente
                       do PATCH /:userId de admin, que redefine direto)
Login, magic link e /auth/me agora devolvem `preferences`, para o
frontend aplicar idioma/tema ja na autenticacao.

Frontend - nova pagina /profile:
- Cartao de identidade (avatar, papel, membro desde, ultimo acesso)
- Dados pessoais (nome editavel; e-mail somente leitura)
- Preferencias: idioma PT/EN e tema claro/escuro/sistema, salvos na
  conta - antes o idioma so vivia no localStorage e nao acompanhava o
  usuario em outro navegador. Aplica na hora e reverte se o save falhar.
- Seguranca: troca de senha

Sidebar passa a apontar para /profile. Textos em pt.json/en.json.
Copilot AI review requested due to automatic review settings August 3, 2026 17:06
@janeiaraujo
janeiaraujo merged commit baa98c7 into main Aug 3, 2026
4 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Este PR adiciona uma página de Perfil do usuário no frontend e cria rotas de auto-serviço no backend para que usuários não-admin consigam visualizar/atualizar preferências (idioma/tema) e trocar a própria senha, além de propagar preferences no payload de autenticação para aplicar idioma/tema já no login.

Changes:

  • Backend: novas rotas /api/users/me, /api/users/me (PATCH) e /api/users/me/password, com validação básica de preferências e troca de senha exigindo senha atual.
  • Backend: login, magic link e /auth/me passam a retornar preferences (language/theme).
  • Frontend: nova página /profile, atualização de AuthContext para aplicar idioma do perfil e ajuste da sidebar/rotas/i18n para suportar o novo fluxo.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
frontend/src/services/api.js Adiciona métodos getMe/updateMe/changePassword para rotas de auto-serviço.
frontend/src/pages/Profile.jsx Implementa UI de perfil (identidade, dados pessoais, preferências e segurança).
frontend/src/i18n/locales/pt.json Adiciona traduções PT para a página de Perfil.
frontend/src/i18n/locales/en.json Adiciona traduções EN para a página de Perfil.
frontend/src/contexts/AuthContext.jsx Aplica idioma salvo em user.preferences durante login/checkAuth e expõe setUser.
frontend/src/components/Sidebar.jsx Atualiza link do usuário para apontar para /profile.
frontend/src/components/Layout.jsx Mapeia /profile para título traduzido no layout.
frontend/src/App.jsx Registra a rota protegida profile.
backend/src/modules/users/users.routes.js Implementa rotas /me (GET/PATCH) e /me/password com validação e auditoria.
backend/src/modules/auth/auth.routes.js Inclui preferences no payload do usuário em login/magic link e /auth/me.
Suppressed comments (2)

backend/src/modules/users/users.routes.js:105

  • Em POST /me/password, o usuário é carregado por _id sem tenant_id. Como o tenant já está disponível via tenantMiddleware e o restante das rotas usa esse filtro, vale manter o escopo por tenant também aqui para garantir isolamento e consistência.
        const user = await db.collection('users').findOne({ _id: request.currentUser._id });

backend/src/modules/users/users.routes.js:120

  • Ainda em POST /me/password, o updateOne que grava o novo hash de senha não filtra por tenant_id. Mesmo que _id normalmente seja único, manter o filtro por tenant reduz risco em cenários de dados inconsistentes e segue o padrão do resto do módulo.
        await db.collection('users').updateOne(
            { _id: user._id },
            { $set: { password: await bcrypt.hash(newPassword, 10), updated_at: new Date() } }
        );

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +52 to +58
if (name !== undefined) {
const trimmed = String(name).trim();
if (!trimmed) {
return reply.status(400).send({ error: 'Nome não pode ficar vazio' });
}
updates.name = trimmed;
}
Comment on lines +84 to +85
const updated = await db.collection('users').findOne({ _id: request.currentUser._id });
return { success: true, user: publicProfile(updated) };
Comment on lines +88 to +102
const handleLanguageChange = async (code) => {
if (code === profile?.preferences?.language) return;
// Aplica na hora; se o salvamento falhar, o idioma volta ao anterior.
const previous = i18n.language;
i18n.changeLanguage(code);
try {
const { data } = await userAPI.updateMe({ preferences: { language: code } });
setProfile(data.user);
syncAuthUser(data.user);
toast.success(t('profile.saved'));
} catch (err) {
i18n.changeLanguage(previous);
toast.error(err.response?.data?.error || t('profile.saveError'));
}
};
Comment on lines +272 to +275
className={currentLanguage === lang.code ? 'border-primary border-2' : ''}
style={{ width: '150px', cursor: 'pointer' }}
onClick={() => handleLanguageChange(lang.code)}
>
Comment on lines +298 to +301
className={theme === item.value ? 'border-primary border-2' : ''}
style={{ width: '150px', cursor: 'pointer' }}
onClick={() => handleThemeChange(item.value)}
>
@janeiaraujo janeiaraujo mentioned this pull request Aug 3, 2026
3 tasks
@janeiaraujo
janeiaraujo deleted the feat/user-profile-preferences branch August 3, 2026 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants