From b273890441a10ca6caa74ff2bcd8adc8118096b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Douglas=20Gon=C3=A7alves?= Date: Thu, 12 Mar 2026 17:09:56 -0300 Subject: [PATCH] commit inicial --- barber-flow-backend/pom.xml | 74 + .../backend/BarberFlowApplication.java | 14 + .../controller/BarbeariaController.java | 38 + .../barberflow/backend/entity/Barbearia.java | 41 + .../barberflow/backend/entity/Barbeiro.java | 37 + .../barberflow/backend/entity/Servico.java | 34 + .../repository/BarbeariaRepository.java | 18 + .../backend/service/BarbeariaService.java | 30 + .../src/main/resources/application.properties | 22 + barber-flow/.gitignore | 41 + barber-flow/GEMINI.md | 83 + barber-flow/README.md | 33 + barber-flow/app.json | 35 + barber-flow/app/[slug]/(auth)/_layout.tsx | 19 + .../app/[slug]/(auth)/forgot-password.tsx | 175 + .../app/[slug]/(auth)/language-selection.tsx | 137 + barber-flow/app/[slug]/(auth)/login.tsx | 193 + barber-flow/app/[slug]/(auth)/register.tsx | 207 + barber-flow/app/[slug]/(tabs)/_layout.tsx | 44 + barber-flow/app/[slug]/(tabs)/agendar.tsx | 549 + barber-flow/app/[slug]/(tabs)/profile.tsx | 358 + barber-flow/app/[slug]/_layout.tsx | 37 + barber-flow/app/[slug]/index.tsx | 96 + barber-flow/app/_layout.tsx | 30 + barber-flow/app/admin/_layout.tsx | 67 + barber-flow/app/admin/agenda.tsx | 268 + barber-flow/app/admin/barber-login.tsx | 154 + barber-flow/app/admin/config.tsx | 622 ++ barber-flow/app/admin/dashboard.tsx | 237 + barber-flow/app/admin/finance.tsx | 192 + barber-flow/app/admin/forgot-password.tsx | 198 + barber-flow/app/admin/login.tsx | 234 + barber-flow/app/admin/register.tsx | 262 + barber-flow/app/index.tsx | 80 + barber-flow/app/landing.tsx | 259 + .../assets/android-icon-background.png | Bin 0 -> 17549 bytes .../assets/android-icon-foreground.png | Bin 0 -> 78796 bytes .../assets/android-icon-monochrome.png | Bin 0 -> 4140 bytes barber-flow/assets/favicon.png | Bin 0 -> 1129 bytes barber-flow/assets/icon.png | Bin 0 -> 393493 bytes barber-flow/assets/splash-icon.png | Bin 0 -> 17547 bytes barber-flow/components/ui/Button.tsx | 125 + barber-flow/components/ui/Card.tsx | 60 + barber-flow/constants/theme.ts | 69 + barber-flow/package-lock.json | 8930 +++++++++++++++++ barber-flow/package.json | 39 + barber-flow/stores/BarbeariaContext.tsx | 344 + barber-flow/stores/LanguageContext.tsx | 287 + barber-flow/tsconfig.json | 6 + barber-flow/vercel.json | 8 + 50 files changed, 14786 insertions(+) create mode 100644 barber-flow-backend/pom.xml create mode 100644 barber-flow-backend/src/main/java/com/barberflow/backend/BarberFlowApplication.java create mode 100644 barber-flow-backend/src/main/java/com/barberflow/backend/controller/BarbeariaController.java create mode 100644 barber-flow-backend/src/main/java/com/barberflow/backend/entity/Barbearia.java create mode 100644 barber-flow-backend/src/main/java/com/barberflow/backend/entity/Barbeiro.java create mode 100644 barber-flow-backend/src/main/java/com/barberflow/backend/entity/Servico.java create mode 100644 barber-flow-backend/src/main/java/com/barberflow/backend/repository/BarbeariaRepository.java create mode 100644 barber-flow-backend/src/main/java/com/barberflow/backend/service/BarbeariaService.java create mode 100644 barber-flow-backend/src/main/resources/application.properties create mode 100644 barber-flow/.gitignore create mode 100644 barber-flow/GEMINI.md create mode 100644 barber-flow/README.md create mode 100644 barber-flow/app.json create mode 100644 barber-flow/app/[slug]/(auth)/_layout.tsx create mode 100644 barber-flow/app/[slug]/(auth)/forgot-password.tsx create mode 100644 barber-flow/app/[slug]/(auth)/language-selection.tsx create mode 100644 barber-flow/app/[slug]/(auth)/login.tsx create mode 100644 barber-flow/app/[slug]/(auth)/register.tsx create mode 100644 barber-flow/app/[slug]/(tabs)/_layout.tsx create mode 100644 barber-flow/app/[slug]/(tabs)/agendar.tsx create mode 100644 barber-flow/app/[slug]/(tabs)/profile.tsx create mode 100644 barber-flow/app/[slug]/_layout.tsx create mode 100644 barber-flow/app/[slug]/index.tsx create mode 100644 barber-flow/app/_layout.tsx create mode 100644 barber-flow/app/admin/_layout.tsx create mode 100644 barber-flow/app/admin/agenda.tsx create mode 100644 barber-flow/app/admin/barber-login.tsx create mode 100644 barber-flow/app/admin/config.tsx create mode 100644 barber-flow/app/admin/dashboard.tsx create mode 100644 barber-flow/app/admin/finance.tsx create mode 100644 barber-flow/app/admin/forgot-password.tsx create mode 100644 barber-flow/app/admin/login.tsx create mode 100644 barber-flow/app/admin/register.tsx create mode 100644 barber-flow/app/index.tsx create mode 100644 barber-flow/app/landing.tsx create mode 100644 barber-flow/assets/android-icon-background.png create mode 100644 barber-flow/assets/android-icon-foreground.png create mode 100644 barber-flow/assets/android-icon-monochrome.png create mode 100644 barber-flow/assets/favicon.png create mode 100644 barber-flow/assets/icon.png create mode 100644 barber-flow/assets/splash-icon.png create mode 100644 barber-flow/components/ui/Button.tsx create mode 100644 barber-flow/components/ui/Card.tsx create mode 100644 barber-flow/constants/theme.ts create mode 100644 barber-flow/package-lock.json create mode 100644 barber-flow/package.json create mode 100644 barber-flow/stores/BarbeariaContext.tsx create mode 100644 barber-flow/stores/LanguageContext.tsx create mode 100644 barber-flow/tsconfig.json create mode 100644 barber-flow/vercel.json diff --git a/barber-flow-backend/pom.xml b/barber-flow-backend/pom.xml new file mode 100644 index 0000000..d649f43 --- /dev/null +++ b/barber-flow-backend/pom.xml @@ -0,0 +1,74 @@ + + + 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.2.4 + + + + com.barberflow + backend + 0.0.1-SNAPSHOT + barber-flow-backend + SaaS Multi-tenant BarberFlow + + + 17 + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + com.h2database + h2 + runtime + + + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + \ No newline at end of file diff --git a/barber-flow-backend/src/main/java/com/barberflow/backend/BarberFlowApplication.java b/barber-flow-backend/src/main/java/com/barberflow/backend/BarberFlowApplication.java new file mode 100644 index 0000000..ce11f54 --- /dev/null +++ b/barber-flow-backend/src/main/java/com/barberflow/backend/BarberFlowApplication.java @@ -0,0 +1,14 @@ +package com.barberflow.backend; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +// @SpringBootApplication diz ao Spring que essa é a classe principal que deve escanear todas as outras pastas e iniciar o servidor. +@SpringBootApplication +public class BarberFlowApplication { + + public static void main(String[] args) { + SpringApplication.run(BarberFlowApplication.class, args); + } + +} \ No newline at end of file diff --git a/barber-flow-backend/src/main/java/com/barberflow/backend/controller/BarbeariaController.java b/barber-flow-backend/src/main/java/com/barberflow/backend/controller/BarbeariaController.java new file mode 100644 index 0000000..bf6a930 --- /dev/null +++ b/barber-flow-backend/src/main/java/com/barberflow/backend/controller/BarbeariaController.java @@ -0,0 +1,38 @@ +package com.barberflow.backend.controller; + +import com.barberflow.backend.entity.Barbearia; +import com.barberflow.backend.service.BarbeariaService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +// @RestController diz ao Spring que essa classe vai receber as requisições HTTP e devolver objetos JSON. +@RestController +// @RequestMapping define que a URL base para todos os métodos aqui dentro será /api/barbearias +@RequestMapping("/api/barbearias") +// @CrossOrigin(*) permite que o seu Front-end no localhost chame esta API sem ser bloqueado pelos navegadores. +@CrossOrigin(origins = "*") +public class BarbeariaController { + + private final BarbeariaService service; + + @Autowired + public BarbeariaController(BarbeariaService service) { + this.service = service; + } + + // @GetMapping indica que este método responde ao protocolo HTTP GET. + // O {slug} na URL é uma variável dinâmica (ex: /api/barbearias/vintage-barber). + @GetMapping("/{slug}") + // @PathVariable pega o {slug} da URL e injeta na variável String slug. + public ResponseEntity getBarbeariaBySlug(@PathVariable String slug) { + try { + Barbearia barbearia = service.buscarPorSlug(slug); + // Retorna um HTTP 200 OK junto com o objeto JSON da Barbearia + return ResponseEntity.ok(barbearia); + } catch (RuntimeException e) { + // Se o Service lançar a exceção de que não achou, retorna um HTTP 404 Not Found + return ResponseEntity.notFound().build(); + } + } +} \ No newline at end of file diff --git a/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Barbearia.java b/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Barbearia.java new file mode 100644 index 0000000..079d4d9 --- /dev/null +++ b/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Barbearia.java @@ -0,0 +1,41 @@ +package com.barberflow.backend.entity; + +import jakarta.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.util.List; +import java.util.ArrayList; + +// @Entity avisa ao Spring/Hibernate que esta classe é uma Tabela no Banco de Dados. +@Entity +// @Data é do Lombok. Ele cria automaticamente os métodos getNome(), setNome(), equals() e toString() por trás dos panos. +@Data +// @NoArgsConstructor cria um construtor vazio obrigatório para o JPA. +@NoArgsConstructor +public class Barbearia { + + // @Id indica que este campo será a Chave Primária (PK) da tabela. + @Id + // @GeneratedValue diz pro banco de dados gerar o ID automaticamente (autoincremento). + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String nome; + + // unique = true indica que duas barbearias não podem ter o mesmo slug (o que garante a exclusividade do tenant). + @Column(unique = true, nullable = false) + private String slug; + + private String logo; // Vamos salvar a URL ou base64 aqui + private String corPrimaria; + private String corSecundaria; + + // Relacionamento 1 para Muitos (Uma Barbearia tem Muitos Serviços). + // mappedBy = "barbearia" indica que a classe Servico é a "dona" do relacionamento. + // cascade = CascadeType.ALL significa que, se você deletar a barbearia, todos os serviços dela também serão deletados no banco. + @OneToMany(mappedBy = "barbearia", cascade = CascadeType.ALL, orphanRemoval = true) + private List servicos = new ArrayList<>(); + + @OneToMany(mappedBy = "barbearia", cascade = CascadeType.ALL, orphanRemoval = true) + private List barbeiros = new ArrayList<>(); +} \ No newline at end of file diff --git a/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Barbeiro.java b/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Barbeiro.java new file mode 100644 index 0000000..818daf9 --- /dev/null +++ b/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Barbeiro.java @@ -0,0 +1,37 @@ +package com.barberflow.backend.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Entity +@Data +@NoArgsConstructor +public class Barbeiro { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String nome; + + @Column(columnDefinition = "TEXT") + private String foto; // Como base64 pode ser muito grande, usamos columnDefinition TEXT + + private Double comissao; // Ex: 50.0 para 50% + + private String email; + + // Ignoramos o password para que não vaze no JSON do Endpoint + @JsonIgnore + private String password; + + private Boolean canViewFinance = false; + private Boolean canEditConfig = false; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "barbearia_id", nullable = false) + @JsonIgnore + private Barbearia barbearia; +} \ No newline at end of file diff --git a/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Servico.java b/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Servico.java new file mode 100644 index 0000000..2f8bb55 --- /dev/null +++ b/barber-flow-backend/src/main/java/com/barberflow/backend/entity/Servico.java @@ -0,0 +1,34 @@ +package com.barberflow.backend.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import lombok.Data; +import lombok.NoArgsConstructor; +import java.math.BigDecimal; + +@Entity +@Data +@NoArgsConstructor +public class Servico { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String nomePt; + private String nomeEs; + + // BigDecimal é a melhor classe do Java para se trabalhar com dinheiro, evitando problemas de arredondamento + private BigDecimal precoPt; + private BigDecimal precoEs; + + private Integer duracao; // Em minutos + + // Relacionamento Muitos para 1 (Muitos Serviços pertencem a Uma Barbearia). + @ManyToOne(fetch = FetchType.LAZY) + // @JoinColumn indica que no banco de dados na tabela Servico será criada uma coluna 'barbearia_id' que aponta pra Barbearia. + @JoinColumn(name = "barbearia_id", nullable = false) + // @JsonIgnore evita um Loop Infinito. Sem ele, ao retornar a Barbearia, ele retorna o Servico, que retorna a Barbearia de novo, quebrando o sistema. + @JsonIgnore + private Barbearia barbearia; +} \ No newline at end of file diff --git a/barber-flow-backend/src/main/java/com/barberflow/backend/repository/BarbeariaRepository.java b/barber-flow-backend/src/main/java/com/barberflow/backend/repository/BarbeariaRepository.java new file mode 100644 index 0000000..1c140a0 --- /dev/null +++ b/barber-flow-backend/src/main/java/com/barberflow/backend/repository/BarbeariaRepository.java @@ -0,0 +1,18 @@ +package com.barberflow.backend.repository; + +import com.barberflow.backend.entity.Barbearia; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +// @Repository indica ao Spring que esta interface vai cuidar das queries ao Banco de Dados. +@Repository +// O JpaRepository traz todos os métodos prontos (save, findAll, deleteById, etc) para a entidade Barbearia. +// O tipo da Chave Primária de Barbearia é Long, por isso passamos . +public interface BarbeariaRepository extends JpaRepository { + + // Apenas declarando o método seguindo a nomenclatura "findBy[Campo]", o Spring constrói a Query SQL automaticamente! + // Equivalente a: SELECT * FROM barbearia WHERE slug = ? + Optional findBySlug(String slug); +} \ No newline at end of file diff --git a/barber-flow-backend/src/main/java/com/barberflow/backend/service/BarbeariaService.java b/barber-flow-backend/src/main/java/com/barberflow/backend/service/BarbeariaService.java new file mode 100644 index 0000000..31c3c9c --- /dev/null +++ b/barber-flow-backend/src/main/java/com/barberflow/backend/service/BarbeariaService.java @@ -0,0 +1,30 @@ +package com.barberflow.backend.service; + +import com.barberflow.backend.entity.Barbearia; +import com.barberflow.backend.repository.BarbeariaRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +// @Service indica que aqui fica a lógica de negócio do sistema (Validações, regras antes de salvar no banco, etc). +@Service +public class BarbeariaService { + + private final BarbeariaRepository repository; + + // @Autowired avisa ao Spring para injetar o Repositório aqui dentro sozinho, sem precisarmos fazer "new BarbeariaRepository()" + @Autowired + public BarbeariaService(BarbeariaRepository repository) { + this.repository = repository; + } + + public Barbearia buscarPorSlug(String slug) { + // Busca a barbearia. Se não achar, lança uma exceção genérica. + return repository.findBySlug(slug) + .orElseThrow(() -> new RuntimeException("Barbearia não encontrada com o slug: " + slug)); + } + + // Criamos esse método para popular nosso banco H2 em memória já que não temos o banco real ainda. + public Barbearia salvar(Barbearia barbearia) { + return repository.save(barbearia); + } +} \ No newline at end of file diff --git a/barber-flow-backend/src/main/resources/application.properties b/barber-flow-backend/src/main/resources/application.properties new file mode 100644 index 0000000..42790ab --- /dev/null +++ b/barber-flow-backend/src/main/resources/application.properties @@ -0,0 +1,22 @@ +spring.application.name=barber-flow-backend + +# Porta onde o back-end vai rodar +server.port=8080 + +# Configurações do Banco de Dados H2 +spring.datasource.url=jdbc:h2:mem:barberflowdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password +spring.jpa.database-platform=org.hibernate.dialect.H2Dialect + +# Permite que o Hibernate crie e atualize as tabelas no banco automaticamente baseado nas nossas classes @Entity +spring.jpa.hibernate.ddl-auto=update + +# Habilita o console do H2 no navegador (acesse: http://localhost:8080/h2-console) +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console + +# Permite que seu app React se comunique com o Spring sem erros de CORS +spring.mvc.cors.allowed-origins=* +spring.mvc.cors.allowed-methods=GET,POST,PUT,DELETE,OPTIONS \ No newline at end of file diff --git a/barber-flow/.gitignore b/barber-flow/.gitignore new file mode 100644 index 0000000..d914c32 --- /dev/null +++ b/barber-flow/.gitignore @@ -0,0 +1,41 @@ +# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files + +# dependencies +node_modules/ + +# Expo +.expo/ +dist/ +web-build/ +expo-env.d.ts + +# Native +.kotlin/ +*.orig.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision + +# Metro +.metro-health-check* + +# debug +npm-debug.* +yarn-debug.* +yarn-error.* + +# macOS +.DS_Store +*.pem + +# local env files +.env*.local + +# typescript +*.tsbuildinfo + +# generated native folders +/ios +/android diff --git a/barber-flow/GEMINI.md b/barber-flow/GEMINI.md new file mode 100644 index 0000000..af2ee11 --- /dev/null +++ b/barber-flow/GEMINI.md @@ -0,0 +1,83 @@ +# BarberFlow SaaS - Project Context + +Este documento serve como a fonte da verdade para a arquitetura, estrutura e regras de negócio do BarberFlow, um sistema SaaS Multi-Tenant para barbearias construído com Expo (React Native). + +## 🚀 Tech Stack Principal +- **Framework:** Expo / React Native (Foco em Web/Mobile First) +- **Roteamento:** Expo Router (File-based routing) +- **Animações & UI:** `react-native-reanimated` (UI/UX Pro Max) +- **Armazenamento:** `@react-native-async-storage/async-storage` (Persistência local temporária/mock) +- **Ícones:** `lucide-react-native` +- **Mídia:** `expo-image-picker` (Imagens convertidas em Base64 para armazenamento) + +## 📁 Estrutura de Diretórios (`app/`) +O projeto utiliza um roteamento baseado no file-system do Expo Router, rigidamente dividido em duas áreas principais após a seleção global de idioma e fluxos de autenticação. + +- `app/index.tsx`: **Raiz Absoluta**. A primeira tela do app. Redireciona para `/landing`. +- `app/landing.tsx`: Landing page comercial do SaaS. Contém botões para acessar "Painel do Dono", "Área do Barbeiro" ou "Ver Demonstração" (Área do Cliente). +- `app/admin/`: **Área Administrativa (O Painel do Dono e do Barbeiro)** + - `_layout.tsx`: Define o Stack protegido do Admin. + - `login.tsx`: Tela de autenticação para o dono da barbearia. + - `barber-login.tsx`: Tela de autenticação separada para funcionários (barbeiros). + - `register.tsx`: Tela de criação de conta (BarberFlow Pro). + - `forgot-password.tsx`: Tela de recuperação de senha. + - `dashboard.tsx`: Visão geral de agendamentos pendentes e confirmados. Permite aceitar, recusar ou cancelar. (A visão é filtrada com base em quem está logado). + - `agenda.tsx`: Tabela visual (Daily Schedule) mostrando os horários de todos os barbeiros e seus status (Livre, Pendente, Confirmado, Bloqueado). + - `finance.tsx`: Tela de gestão financeira, exibindo faturamento bruto e o cálculo de comissão exato para cada barbeiro. + - `config.tsx`: **Wizard de 6 Passos** para configurar a barbearia (Identidade, Localização, Serviços, Barbeiros, Formas de Pagamento, Link Final). +- `app/[slug]/`: **Área do Cliente (Multi-Tenant)** + - `_layout.tsx`: Provedor de contexto específico do tenant (barbearia). + - `index.tsx`: Tela inicial de redirecionamento do tenant para o fluxo de idioma/auth. + - `(auth)/`: **Autenticação e Pré-requisitos do Cliente** + - `language-selection.tsx`: O cliente escolhe o idioma (PT/ES) e a moeda (R$/GS) que prefere ser atendido. + - `login.tsx`: Tela de login do cliente. Redireciona para o agendamento após sucesso. + - `register.tsx`: Tela de cadastro do cliente. + - `forgot-password.tsx`: Tela de recuperação de senha. + - `(tabs)/`: **Área Interna do Cliente** + - `_layout.tsx`: Tab bar com as opções principais. + - `agendar.tsx`: O core do lado do cliente. Fluxo de 3 passos: Escolher Serviço/Barbeiro -> Escolher Data/Hora -> Pagamento & Confirmação. + - `profile.tsx`: Perfil do cliente com histórico. + +## 🧠 Gerenciamento de Estado (Contextos) + +### 1. `BarbeariaContext.tsx` +O "banco de dados" do sistema. Gerencia os dados da barbearia atual (Tenant). +- **Resiliência do Slug:** Se o usuário acessa um `slug` e ele bate com o do AsyncStorage, os dados carregam. +- **Role-Based Access Control (RBAC):** Armazena a variável `activeBarberId`. Se for `null`, o sistema entende que é o dono e libera tudo. Se tiver um ID de funcionário logado, restringe as views. +- **Estruturas Principais:** + - `services`: Contém nomes, preços bilíngues e duração (`nomePt`, `nomeEs`, `precoPt`, `precoEs`, `duracao`). + - `barbers`: Lista de profissionais contendo `nome`, `foto`, `commission`, `email`, `password` e `permissions` (`canViewFinance`, `canEditConfig`). + - `paymentMethods`: Array de strings (ex: `['pix', 'card', 'money', 'alias']`). + - `appointments`: Lista de agendamentos com status e valor total do serviço. + +### 2. `LanguageContext.tsx` +Coração do sistema i18n e regras de moeda. +- **Tradução:** A função `t(key)` é robusta contra chaves não encontradas ou parâmetros `undefined`. +- **Preços (`formatPrice`):** Recebe dois valores e formata com base no idioma atual (Real R$ ou Guarani GS). + +## ⚖️ Regras de Negócio Críticas + +1. **Separação Dono vs Funcionário vs Cliente:** + - **Dono:** Acessa via `/admin/login`. Visualiza e edita todas as configurações, visualiza a agenda de todos e acessa o balanço financeiro geral. + - **Barbeiro (Funcionário):** Acessa via `/admin/barber-login`. Ao logar, vai para o Dashboard onde **só visualiza os seus próprios agendamentos**. Na agenda, não consegue clicar/bloquear a agenda de colegas. O acesso a configurações e financeiro depende de flags explícitas de permissão no cadastro dele. + - **Cliente:** Acessa via `/[slug]`, faz autenticação e visualiza os horários disponíveis (área em `(tabs)`). + +2. **Fluxo de Agendamento e Edição (Admin):** + - Na tela `config.tsx`, o admin consegue criar e agora também **editar** informações de barbeiros e serviços sem precisar deletá-los. + - A agenda do admin e do barbeiro permite selecionar múltiplos horários em massa (multi-select) e aplicar a ação "Bloquear" ou "Liberar". + +3. **Sistema Financeiro e Comissionamento:** + - O sistema rastreia o valor gerado nos agendamentos `accepted` e calcula de forma individual o repasse do barbeiro com base na porcentagem (`%`) cadastrada no seu perfil. + - Se um barbeiro com permissão de ver as finanças acessar a tela, ele **só enxergará o valor do próprio caixa e o valor que ele vai receber**, enquanto o dono enxerga a somatória bruta de todos. + +4. **Lógica de Formas de Pagamento Dinâmicas:** + - O admin marca os métodos aceitos na aba de configurações. A lista sofre filtro dinâmico de moeda (O cliente que escolheu idioma Espanhol não vê PIX, e o cliente do Português não vê Alias). + +5. **Tratamento de Imagens:** + - O upload de logos e avatares converte o binário para `Base64` injetando diretamente no estado e no AsyncStorage. + +## 🎨 Padrão de UI/UX (Pro Max) +Todas as telas seguem o manual de referências UI/UX. +- **Animações:** `FadeInUp`, `FadeInDown`, e `FadeInRight` usando `react-native-reanimated` para navegação suave. +- **Feedback Tátil:** `expo-haptics` acionados ao confirmar botões de bloqueio e salvar perfis. +- **Design Responsivo:** Uso do `useWindowDimensions()` nas telas web para garantir que, no iPhone ou Android, os painéis colapsem na vertical (flex-col) de ponta a ponta com segurança visual (`paddingHorizontal: 16`). \ No newline at end of file diff --git a/barber-flow/README.md b/barber-flow/README.md new file mode 100644 index 0000000..28cf0fa --- /dev/null +++ b/barber-flow/README.md @@ -0,0 +1,33 @@ +# BarberFlow - Agendamento Moderno + +Um projeto de agendamento de barbearia moderno construído com React Native (Expo), TypeScript e Reanimated. + +## Tecnologias Utilizadas +- **Expo Router**: Navegação baseada em arquivos. +- **Lucide Icons**: Ícones modernos e consistentes. +- **Reanimated 3**: Animações fluidas e de alta performance. +- **Safe Area Context**: Layout adaptável a diferentes telas. +- **Haptics**: Feedback tátil para interações. + +## Estrutura do Projeto +- `app/`: Contém as rotas e telas (Início, Agendar, Perfil). +- `components/ui/`: Componentes reutilizáveis (Button, Card). +- `constants/theme.ts`: Definição de cores, espaçamento e tipografia. + +## Como Executar +O servidor já está sendo iniciado em segundo plano. + +Para ver no navegador: +1. Pressione `ctrl + f` para focar no terminal se necessário. +2. Abra o link exibido no terminal (geralmente `http://localhost:8081`). + +Para abrir no VS Code: +```bash +code . +``` + +## Funcionalidades +- [x] Home com serviços e barbeiros em destaque. +- [x] Agendamento com seleção de data e hora. +- [x] Perfil do usuário com estatísticas e menu. +- [x] Design escuro (Gold & Dark) de luxo. diff --git a/barber-flow/app.json b/barber-flow/app.json new file mode 100644 index 0000000..9cd96c6 --- /dev/null +++ b/barber-flow/app.json @@ -0,0 +1,35 @@ +{ + "expo": { + "name": "barber-flow", + "slug": "barber-flow", + "version": "1.0.0", + "orientation": "portrait", + "icon": "./assets/icon.png", + "userInterfaceStyle": "dark", + "scheme": "barber-flow", + "splash": { + "image": "./assets/splash-icon.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "ios": { + "supportsTablet": true + }, + "android": { + "adaptiveIcon": { + "backgroundColor": "#E6F4FE", + "foregroundImage": "./assets/android-icon-foreground.png", + "backgroundImage": "./assets/android-icon-background.png", + "monochromeImage": "./assets/android-icon-monochrome.png" + }, + "predictiveBackGestureEnabled": false + }, + "web": { + "favicon": "./assets/favicon.png" + }, + "plugins": [ + "expo-router", + "expo-font" + ] + } +} diff --git a/barber-flow/app/[slug]/(auth)/_layout.tsx b/barber-flow/app/[slug]/(auth)/_layout.tsx new file mode 100644 index 0000000..36b5458 --- /dev/null +++ b/barber-flow/app/[slug]/(auth)/_layout.tsx @@ -0,0 +1,19 @@ +import { Stack } from 'expo-router'; +import { COLORS } from '../../../constants/theme'; + +export default function AuthLayout() { + return ( + + + + + + + ); +} diff --git a/barber-flow/app/[slug]/(auth)/forgot-password.tsx b/barber-flow/app/[slug]/(auth)/forgot-password.tsx new file mode 100644 index 0000000..1d93ded --- /dev/null +++ b/barber-flow/app/[slug]/(auth)/forgot-password.tsx @@ -0,0 +1,175 @@ +import React, { useState } from 'react'; +import { View, Text, StyleSheet, TextInput, Pressable, KeyboardAvoidingView, Platform, Alert, Image, ScrollView } from 'react-native'; +import { router } from 'expo-router'; +import Animated, { FadeInDown, FadeInUp } from 'react-native-reanimated'; +import { COLORS, SPACING, TYPOGRAPHY, BORDER_RADIUS, SHADOWS } from '../../../constants/theme'; +import { Button } from '../../../components/ui/Button'; +import { Mail, Scissors, ChevronLeft } from 'lucide-react-native'; +import * as Haptics from 'expo-haptics'; +import { useLanguage } from '../../../stores/LanguageContext'; +import { useBarbearia } from '../../../stores/BarbeariaContext'; +import { SafeAreaView } from 'react-native-safe-area-context'; + +export default function ForgotPasswordScreen() { + const { t } = useLanguage(); + const { barbearia } = useBarbearia(); + const colors = barbearia?.colors || COLORS; + + const [email, setEmail] = useState(''); + const [isLoading, setIsLoading] = useState(false); + + const handleRecover = async () => { + if (!email) { + if (Platform.OS === 'web') { + window.alert(t('admin.config.fill_all') || 'Preencha o e-mail'); + } else { + Alert.alert('Erro', t('admin.config.fill_all') || 'Preencha o e-mail'); + } + return; + } + + setIsLoading(true); + Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); + + // Simulação de recuperação + setTimeout(() => { + setIsLoading(false); + if (Platform.OS === 'web') { + window.alert('Instruções enviadas para o seu e-mail.'); + } else { + Alert.alert('Sucesso', 'Instruções enviadas para o seu e-mail.'); + } + router.back(); + }, 1500); + }; + + return ( + + + router.back()} + > + + {t('book.back') || 'Voltar'} + + + + + + {barbearia?.logo ? ( + + ) : ( + + )} + + + Recuperar Senha + + Enviaremos as instruções para seu e-mail. + + + + + + + + + +