🚀 Demo Online: https://trackbalance123.netlify.app
Uma aplicação web para controle de finanças pessoais desenvolvida como projeto de aprendizado e portfólio.
| Desktop Home | Desktop Login | Desktop Otp |
|---|---|---|
![]() |
![]() |
![]() |
| Desktop Dashboard Cima | Desktop Dashboard Baixo |
|---|---|
![]() |
![]() |
| Desktop Sidebar | Desktop Modal |
|---|---|
![]() |
![]() |
| Mobile Dashboard Cima | Mobile Dashboard Baixo | Mobile Home |
|---|---|---|
![]() |
![]() |
![]() |
| Mobile Sidebar | Mobile Modal |
|---|---|
![]() |
![]() |
- Gestão de Receitas: Inserir, atualizar e deletar receita mensal (uma única receita por mês)
- Gestão de Despesas: Inserir, atualizar e deletar múltiplas despesas (categorias únicas por mês)
- Navegação entre Meses: Acessar e manipular dados de meses anteriores e futuros (dentro dos limites estabelecidos)
- Exportação de Dados: Exportar dados do mês atual para CSV e PDF
- Dashboard Resumido: Visualização rápida do saldo e despesas recentes
- Exclusão de Conta: Remoção completa dos dados do usuário
- Gestão dos Meses:
- Não cria meses desnecessários (apenas cria quando há dados reais)
- Detecta "meses vazios" no histórico e oferece preenchimento automático
- Sempre garante que o mês atual existe, copiando dados do último mês válido
- Cria meses intermediários automaticamente durante a navegação nos meses (caso queira navegar para um mês que não existe)
- Frontend: React + Vite
- Backend: Supabase (Banco de dados e autenticação OTP)
- Roteamento: React Router
- Gráficos: Recharts
- Exportação PDF: jsPDF + AutoTables
- Estilização: CSS
Desenvolvi este projeto com grande foco em acessibilidade:
Embora este projeto seja para portfólio, ele é também (até mais) de aprendizado. Como tal, queria aprender a criar componentes "substitutos" aos elementos nativos e acima de tudo aprender a deixar-los acessíveis.
Em todos os componentes customizados, segui como referência principal o WAI-ARIA Authoring Practices Guide (APG). Em alguns componentes adaptei para a minha situação (alguns ajustes em timeout, para gerenciar melhor o foco e o comportamento do leitor de tela), mas o "grosso", leia-se atributos aria, focus trap e tudo o resto segui os padrões recomendados.
- Modal Context - substitui alertas/confirms nativos
- CustomSelect - acessível com focus trap, type-ahead e anuncios
- NumberInput - mantive o input type number nativo, adicionei botões + e -, escondi e desativei o spinner
- FormModal - modal genérico para formulários
- useAriaActionStatusAnnouncer - gerencia live regions para feedback em tempo real
- useFormFieldValidation - validações customizadas com feedback acessível
- Navegação completa via teclado (todas as funcionalidades)
- Teste com leitor de tela Orca + navegador Firefox (Linux)
- Navegação por landmarks e headings
- Teste de focus trap em modais
- Validação de contrastes de cor
- Lighthouse
- WAVE Evaluation Tool
- IBM Equal Access Accessibility Checker
- Ferramenta nativa de Acessibilidade do Firefox
Contexto:
A barra de ações do usuário (inserir receita, despesas etc.) antes fechava automaticamente ao abrir algum modal.
O problema:
Quando o primeiro elemento focado no modal era um input:
- ✅ Ao abrir: Leitor anunciava "Recolhido" → título do modal → label do input
- ✅ Ao fechar: Foco voltava ao botão de Menu, leitor lia "Recolhido"
- ❌ Bug: Ao pressionar o botão para abrir a barra, o leitor não anunciava "Expandido"
Observações:
- Isso não acontecia quando o primeiro elemento era um
select(como meu componente customizado) - Acontecia apenas no deploy - em desenvolvimento local tudo funcionava perfeitamente.
Minha solução:
Após várias tentativas sem sucesso, optei por:
- A barra agora só fecha quando o usuário clica explicitamente no botão de Menu
- Não fecha mais automaticamente ao abrir modais
Honestamente:
Não sei se é um comportamento específico do leitor de tela (Orca + Firefox) ou se fiz algo errado no código (mais provável né...!!! 😅). Mas com essa mudança, tudo funciona corretamente! ✅
- months: Controle de meses por usuário
- incomes: Receitas mensais (uma por mês)
- expenses: Despesas mensais (categorias únicas)
- user_flags: Controle de navegação entre meses - enquanto flags forem null, quer dizer que o usuario não colocou dados uteis (receita e ou despesas). Não cria registro de mês.
- Node.js instalado
- Conta no Supabase
- Clone o repositório:
git clone https://github.com/pedrobfernandes/trackbalance.git
cd trackbalance- Instale as dependências:
npm install- Configure as variáveis de ambiente:
- Crie um arquivo .env na raíz do projeto
- Adicione as suas credencias do Supabase:
VITE_SUPABASE_URL=sua_url_do_supabase
VITE_SUPABASE_ANON_KEY=sua_chave_anon_publica
VITE_SUPABASE_DELETE_ACCOUNT_URL=url_da_edge_function_para_excluir_conta- Configure o banco de dados
- Crie um projeto no Supabase
- Execute o script que está na pasta
database/setup.sqlno editor SQL do projeto - Crie uma Edge Function com o nome:
delete-user-account - Configure a Edge Function
delete-user-accountusando o arquivo da pastadatabase/delete-user-account/index.ts - No dashboard do Supabase, procure pelos templates de Email, e use o template da pasta
email-templatepara "Confirm sign up" e "Magic link"
- Execute a aplicação
npm run dev- A autenticação é por OTP (código enviado para o email)
- Usei o mesmo template de email para "Confirm Signup" e "Magic Link", caso contrário, no segundo login, o Supabase envia Magic Link ao invés de código
- Como iniciante, configurei a Edge Function (e basicamente tudo) pelo dashboard do Supabase, sem usar supabase-cli ou outro método
- Todos os testes de acessibilidade foram feitos no Firefox (Linux) + Orca apenas. Não garanto nada em outra combinação de sistema/navegador/leitor.











