Visão Geral do Frontend
O frontend da QuettaCode Platform é construído com Next.js 16 e React 19, utilizando o App Router.
Estrutura de Pastas
apps/web/src/
├── app/ # App Router (páginas)
│ ├── (app)/ # Layout autenticado
│ │ ├── dashboard/
│ │ ├── conversations/
│ │ ├── contacts/
│ │ ├── campaigns/
│ │ └── settings/
│ ├── (auth)/ # Layout de autenticação
│ │ ├── login/
│ │ └── register/
│ └── layout.tsx # Root layout
├── components/ # Componentes específicos da app
├── hooks/ # Custom hooks
├── services/ # Chamadas à API
├── store/ # Zustand stores
├── providers/ # Context providers
└── lib/ # Utilitários
App Router vs Pages Router
A aplicação usa o App Router (pasta app/), não o Pages Router.
Características
| Feature | Descrição |
|---|---|
| Server Components | Componentes padrão são Server Components |
| Client Components | Use 'use client' no topo do arquivo |
| Layouts | layout.tsx compartilhado entre rotas filhas |
| Loading | loading.tsx para estados de carregamento |
| Error | error.tsx para tratamento de erros |
Route Groups
Usamos Route Groups (parênteses) para organização:
app/
├── (app)/ # Rotas que requerem autenticação
└── (auth)/ # Rotas públicas de autenticação
Os parênteses não afetam a URL final.
Server vs Client Components
Server Components (Padrão)
// Não precisa de 'use client'
// Roda apenas no servidor
async function DashboardPage() {
const data = await fetchData(); // Dados no servidor
return <Dashboard data={data} />;
}
Client Components
'use client';
// Roda no cliente (browser)
// Necessário para hooks, eventos, etc.
import { useState } from 'react';
function InteractiveComponent() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}
Design System
Os componentes de UI estão no pacote @quettacode/ui:
import { Button, Input, Dialog } from '@quettacode/ui';
Ver Design System → para lista completa.
Gerenciamento de Estado
Zustand (Global)
Estado global gerenciado com Zustand:
// store/useAuthStore.ts
import { create } from 'zustand';
interface AuthState {
user: User | null;
token: string | null;
setUser: (user: User) => void;
}
export const useAuthStore = create<AuthState>((set) => ({
user: null,
token: null,
setUser: (user) => set({ user }),
}));
React Hook Form (Formulários)
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
const form = useForm({
resolver: zodResolver(schema),
});
Estilização
Tailwind CSS 4
<div className="flex items-center gap-4 p-4 bg-background rounded-lg">
<span className="text-foreground font-medium">Hello</span>
</div>
CSS Variables (Temas)
/* Definidas em globals.css */
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
}