Skip to content

Commit 31f8f49

Browse files
Merge pull request #7 from wellington1993/feature/architectural-refactor
test(ui): adiciona cobertura para componentes compartilhados
2 parents 73d7568 + 1815746 commit 31f8f49

90 files changed

Lines changed: 4737 additions & 1730 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,77 @@
1-
# Flugo Staff Manager
1+
# Flugo Employees
22

3-
Gerenciador de colaboradores feito com React + Firebase. Formulário multi-etapa com rascunho automático e sincronização com o Firestore.
3+
Este é o sistema de gestão de colaboradores e times da Flugo. Ele foi construído com foco em resiliência e facilidade de manutenção, usando uma arquitetura limpa que separa bem as regras de negócio da infraestrutura técnica.
44

5-
Demo: [https://flugo-employees-theta.vercel.app](https://flugo-employees-theta.vercel.app)
5+
Demo online: [https://flugo-employees-theta.vercel.app](https://flugo-employees-theta.vercel.app)
66

7-
---
7+
## O que tem dentro?
88

9-
## Stack
9+
- **React 19 + TypeScript:** O core da aplicação com a última versão do React.
10+
- **Material UI v7:** Toda a interface visual e componentes de UI.
11+
- **Firebase (Auth + Firestore):** Controle de acesso e banco de dados em tempo real.
12+
- **TanStack Query v5:** Gerenciamento inteligente de estado e cache de dados.
13+
- **Clean Architecture:** Código organizado em camadas (Domínio, Aplicação, Infra e Apresentação).
14+
- **Service Workers:** Estratégias avançadas de caching e sincronização de dados em segundo plano.
1015

11-
- React 19 + TypeScript + Vite
12-
- Material UI v7 + Emotion
13-
- TanStack Query v5
14-
- React Hook Form + Zod
15-
- Firebase Firestore
16-
- React Router v7
16+
## Como rodar na sua máquina
1717

18-
---
19-
20-
## Como rodar
21-
22-
**Localmente**
18+
Primeiro, clone o repositório e instale as dependências:
2319

2420
```bash
2521
npm install
26-
# configure o .env com base no .env.example
27-
npm run dev
28-
# http://localhost:5173
2922
```
3023

31-
**Com Docker**
24+
### Configurando o ambiente
25+
26+
Você vai precisar de um arquivo `.env.local` na raiz do projeto. Use o `.env.example` como base e preencha com as suas chaves do Firebase:
27+
28+
```env
29+
VITE_FIREBASE_API_KEY=sua_chave
30+
VITE_FIREBASE_AUTH_DOMAIN=seu_projeto.firebaseapp.com
31+
VITE_FIREBASE_PROJECT_ID=seu_projeto
32+
VITE_FIREBASE_STORAGE_BUCKET=seu_projeto.appspot.com
33+
VITE_FIREBASE_MESSAGING_SENDER_ID=seu_sender_id
34+
VITE_FIREBASE_APP_ID=seu_app_id
35+
```
36+
37+
### Rodando o projeto
38+
39+
Para iniciar o servidor de desenvolvimento:
3240

3341
```bash
34-
docker compose up --build
35-
# http://localhost:3000
42+
npm run dev
3643
```
3744

38-
---
45+
Abra [http://localhost:5173](http://localhost:5173) no navegador.
3946

40-
## Testes
47+
### Build de Produção
48+
49+
Para gerar a versão final otimizada:
4150

4251
```bash
43-
npm run test # unitários (Vitest)
44-
npm run test:e2e # E2E (Playwright)
52+
`npm run build
53+
npm run preview
4554
```
4655

47-
---
56+
## Configurando o Firebase
57+
58+
59+
Para que tudo funcione, você precisa ativar dois serviços no seu console do Firebase:
4860

49-
## Firebase
61+
1. **Authentication:** Ative o provedor de **E-mail/Senha**.
62+
2. **Cloud Firestore:** Crie o banco de dados.
5063

51-
1. Crie um projeto no Firebase Console
52-
2. Ative o Firestore em modo de teste
53-
3. Copie as chaves web para o `.env`
64+
### Regras de Segurança
5465

55-
As regras de segurança estão em `firestore.rules`. Para publicar:
66+
Para aplicar as regras do banco de dados (que estão no arquivo `firestore.rules`), você pode usar o CLI do Firebase:
5667

5768
```bash
58-
npx firebase-tools deploy --only firestore:rules --project SEU_ID
69+
npx firebase-tools deploy --only firestore:rules --project SEU_ID_DO_PROJETO
5970
```
71+
72+
## Testes
73+
74+
Temos uma boa cobertura de testes para garantir que nada quebre ao adicionar novas funções:
75+
76+
- **Unitários:** `npm run test` (testamos a lógica de negócio isolada).
77+
- **E2E:** `npm run test:e2e` (testamos o fluxo completo no navegador com Playwright).

docker-compose.yml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,7 @@ services:
22
app:
33
build:
44
context: .
5-
args:
6-
- VITE_FIREBASE_API_KEY=${VITE_FIREBASE_API_KEY}
7-
- VITE_FIREBASE_AUTH_DOMAIN=${VITE_FIREBASE_AUTH_DOMAIN}
8-
- VITE_FIREBASE_PROJECT_ID=${VITE_FIREBASE_PROJECT_ID}
9-
- VITE_FIREBASE_STORAGE_BUCKET=${VITE_FIREBASE_STORAGE_BUCKET}
10-
- VITE_FIREBASE_MESSAGING_SENDER_ID=${VITE_FIREBASE_MESSAGING_SENDER_ID}
11-
- VITE_FIREBASE_APP_ID=${VITE_FIREBASE_APP_ID}
12-
- VITE_BASE_URL=/
135
ports:
146
- "8080:80"
157
env_file:
16-
- .env
8+
- .env.local

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@
66
"scripts": {
77
"dev": "vite",
88
"build": "tsc -b && vite build",
9+
"start": "vite preview --host 0.0.0.0",
10+
"heroku-postbuild": "npm run build",
911
"lint": "eslint .",
1012
"preview": "vite preview",
1113
"test": "vitest",
1214
"test:run": "vitest run",
1315
"test:coverage": "vitest run --coverage",
1416
"test:e2e": "playwright test tests/e2e/staff.spec.ts",
15-
"test:smoke": "playwright test tests/e2e/smoke.spec.ts"
17+
"test:smoke": "playwright test tests/e2e/smoke.spec.ts",
18+
"db:purge": "tsx scripts/purge-test-data.ts"
1619
},
1720
"dependencies": {
1821
"@emotion/react": "^11.14.0",
@@ -27,6 +30,7 @@
2730
"firebase": "^12.10.0",
2831
"react": "^19.2.0",
2932
"react-dom": "^19.2.0",
33+
"react-firebase-hooks": "^5.1.1",
3034
"react-hook-form": "^7.71.2",
3135
"react-router-dom": "^7.13.1",
3236
"zod": "^4.3.6"

scripts/purge-test-data.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { initializeApp } from 'firebase/app';
2+
import { getFirestore, collection, getDocs, deleteDoc, doc, query, where } from 'firebase/firestore';
3+
import * as dotenv from 'dotenv';
4+
import path from 'path';
5+
import { fileURLToPath } from 'url';
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
10+
dotenv.config({ path: path.resolve(__dirname, '../.env.local') });
11+
12+
const firebaseConfig = {
13+
apiKey: process.env.VITE_FIREBASE_API_KEY,
14+
authDomain: process.env.VITE_FIREBASE_AUTH_DOMAIN,
15+
projectId: process.env.VITE_FIREBASE_PROJECT_ID,
16+
storageBucket: process.env.VITE_FIREBASE_STORAGE_BUCKET,
17+
messagingSenderId: process.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
18+
appId: process.env.VITE_FIREBASE_APP_ID,
19+
};
20+
21+
async function purge() {
22+
if (!firebaseConfig.projectId) {
23+
console.error('Firebase Project ID não encontrado no .env.local');
24+
return;
25+
}
26+
27+
const app = initializeApp(firebaseConfig);
28+
const db = getFirestore(app);
29+
30+
const collections = ['staffs', 'departments'];
31+
const patterns = ['Error', 'Optimistic User', 'Teste', 'Scalability'];
32+
33+
for (const colName of collections) {
34+
console.log(`Limpando coleção: ${colName}...`);
35+
const colRef = collection(db, colName);
36+
const snapshot = await getDocs(colRef);
37+
38+
let count = 0;
39+
for (const document of snapshot.docs) {
40+
const data = document.data();
41+
const name = data.name || '';
42+
43+
const shouldDelete = patterns.some(p => name.includes(p));
44+
45+
if (shouldDelete) {
46+
await deleteDoc(doc(db, colName, document.id));
47+
count++;
48+
}
49+
}
50+
console.log(`Removidos ${count} documentos de ${colName}.`);
51+
}
52+
}
53+
54+
purge().catch(console.error);

src/App.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import { Sidebar } from '@/components/sidebar'
66
import { Header } from '@/components/header'
77
import { Breadcrumb } from '@/components/breadcrumb'
88
import { useSyncPending } from '@/features/staff/hooks'
9+
import { ConnectivityIndicator } from '@/components/connectivity-indicator'
910

1011
function App() {
1112
const [mobileOpen, setMobileOpen] = useState(false)
1213
const theme = useTheme()
1314
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
1415

15-
// Ativa a sincronização em segundo plano
1616
useSyncPending()
1717

1818
const handleDrawerToggle = () => {
@@ -21,6 +21,7 @@ function App() {
2121

2222
return (
2323
<Box sx={{ display: 'flex', minHeight: '100vh', bgcolor: 'background.default' }}>
24+
<ConnectivityIndicator />
2425
<Sidebar mobileOpen={mobileOpen} onClose={handleDrawerToggle} />
2526
<Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', width: '100%' }}>
2627
<Header>
@@ -36,8 +37,8 @@ function App() {
3637
</IconButton>
3738
)}
3839
</Header>
39-
<Box component="main" sx={{ flex: 1, p: { xs: 2, md: 5 }, width: '100%' }}>
40-
<Container maxWidth="md" disableGutters>
40+
<Box component="main" sx={{ flex: 1, p: { xs: 1.5, sm: 2.5, md: 4 }, width: '100%' }}>
41+
<Container maxWidth="xl" disableGutters>
4142
<Breadcrumb />
4243
<Outlet />
4344
</Container>

0 commit comments

Comments
 (0)