diff --git a/.dockerignore b/.dockerignore index 626401c..7c40398 100644 --- a/.dockerignore +++ b/.dockerignore @@ -34,8 +34,9 @@ deploy.sh # Documentation *.md -API_TESTING_GUIDE.md -DEPLOYMENT_README.md +# Keep deployment guides in production image +!DEPLOYMENT_README.md +!API_TESTING_GUIDE.md # Testing coverage diff --git a/.env.example b/.env.example index b5c3596..35f0ff2 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,10 @@ RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx # App NEXT_PUBLIC_APP_URL=http://localhost:3000 +# Formbricks (Surveys - Optional) +NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=your-environment-id +NEXT_PUBLIC_FORMBRICKS_API_HOST=https://app.formbricks.com + # Optional: Redis para caching REDIS_URL=redis://redis:6379 diff --git a/API_TESTING_GUIDE.md b/API_TESTING_GUIDE.md index f2c8017..c47ba07 100644 --- a/API_TESTING_GUIDE.md +++ b/API_TESTING_GUIDE.md @@ -83,6 +83,74 @@ - `POST /api/cron/reset-invitations` - Reset diario - Buscar: Invitaciones expiradas reseteadas +### **📧 Webhooks (Formularios Públicos)** +- `POST https://flows.soul23.cloud/webhook-test/4YZ7RPfo1GT` - Webhook test + - Body: Payload completo con form type + - Buscar: 200 OK + acknowledgment +- `POST https://flows.soul23.cloud/webhook/4YZ7RPfo1GT` - Webhook prod + - Body: Payload completo con form type + - Buscar: 200 OK + acknowledgment + +**Form Types disponibles:** +- `contact` - Formulario de contacto +- `franchise` - Solicitud de franquicia +- `membership` - Solicitud de membresía + +**Payload Base:** +```json +{ + "form": "contact|franchise|membership", + "timestamp_utc": "2026-01-18T04:26:30.187Z", + "device_type": "mobile|desktop|unknown" +} +``` + +**Contact Payload:** +```json +{ + "form": "contact", + "nombre": "Nombre Completo", + "email": "email@example.com", + "telefono": "+52 844 123 4567", + "motivo": "cita|membresia|franquicia|servicios|pago|resena|otro", + "mensaje": "Texto del mensaje", + "timestamp_utc": "2026-01-18T04:26:30.187Z", + "device_type": "mobile" +} +``` + +**Franchise Payload:** +```json +{ + "form": "franchise", + "nombre": "Nombre Completo", + "email": "email@example.com", + "telefono": "+52 844 123 4567", + "ciudad": "Monterrey", + "estado": "Nuevo León", + "socios": 2, + "experiencia_sector": "1-3-anos", + "experiencia_belleza": true, + "mensaje": "Mensaje adicional", + "timestamp_utc": "2026-01-18T04:26:30.187Z", + "device_type": "desktop" +} +``` + +**Membership Payload:** +```json +{ + "form": "membership", + "membership_id": "vip", + "nombre": "Nombre Completo", + "email": "email@example.com", + "telefono": "+52 844 123 4567", + "mensaje": "Pregunta específica", + "timestamp_utc": "2026-01-18T04:26:30.187Z", + "device_type": "mobile" +} +``` + ## 🔍 **Qué Buscar en Cada Respuesta** ### **✅ Éxito** diff --git a/ASSETS_PLAN.md b/ASSETS_PLAN.md index 0bb72ad..4b40ae7 100644 --- a/ASSETS_PLAN.md +++ b/ASSETS_PLAN.md @@ -154,7 +154,30 @@ public/images/gallery/ --- -## 8. Logo SVG Original (@src/logo.svg) +## 8. Nuevos Componentes (@src/components/) + +**Ubicación sugerida:** `components/` + +**Componentes agregados:** +- `animated-logo.tsx` - Logo SVG animado con fade-in +- `rolling-phrases.tsx` - Frases rotativas para hero sections +- `formbricks-provider.tsx` - Provider para encuestas Formbricks +- `webhook-form.tsx` - Formulario unificado para webhooks +- `app-wrapper.tsx` - Wrapper de aplicación con contexto +- `loading-screen.tsx` - Pantalla de carga con animación +- `pattern-overlay.tsx` - Overlay de patrones decorativos +- `responsive-nav.tsx` - Navegación responsiva con menú móvil + +**Iconos adicionales:** +- Diamond (check, success states) +- Crown (VIP tier) + +**Colores actualizados:** +- `--charcoal-brown`: #3f362e (marrón oscuro elegante) +- `--deep-earth`: #6f5e4f (marrón medio) +- `--mocha-taupe`: #b8a89a (beige cálido) + +## 9. Logo SVG Original (@src/logo.svg) **Ruta:** `src/logo.svg` @@ -332,6 +355,30 @@ public/images/gallery/ --- +## 📋 21. Formbricks Integration + +**Ubicación:** `components/formbricks-provider.tsx` + +**Configuración:** +- Environment ID para surveys +- API Host URL +- Device detection (mobile/desktop) +- Route change tracking + +**Variables de entorno:** +```bash +NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=your-id +NEXT_PUBLIC_FORMBRICKS_API_HOST=https://app.formbricks.com +``` + +**Uso previsto:** +- Encuestas post-experiencia +- Feedback de clientes +- NPS (Net Promoter Score) +- Estudios de satisfacción + +--- + ## 📋 Checklist de Implementación | Tarea | Estado | Prioridad | @@ -340,6 +387,17 @@ public/images/gallery/ | Optimizar imágenes A23_VIA_* | pending | alta | | Implementar logo SVG en Hero sin animación | completed | alta | | Implementar logo SVG en Loading sin fade-in| completed | alta | +| Crear componente animated-logo.tsx | completed | alta | +| Crear componente rolling-phrases.tsx | completed | alta | +| Crear componente webhook-form.tsx | completed | alta | +| Crear componente formbricks-provider.tsx | completed | media | +| Crear componente responsive-nav.tsx | completed | alta | +| Actualizar colores a #3E352E | completed | alta | +| Agregar campo motivo en contacto | completed | alta | +| Agregar campos estado/ciudad/socios en franchise | pending | alta | +| Agregar check experiencia belleza en franchise | pending | alta | +| Actualizar info franchise a $100k | completed | alta | +| Agregar link Contacto en nav/footer | completed | alta | | Agregar imágenes Hero/Fundamento | pending | media | | Agregar imágenes Historia | pending | media | | Agregar testimonios | pending | media | @@ -360,6 +418,12 @@ public/images/gallery/ - **Background Loading:** #3F362E (Marrón oscuro elegante) - **Gradient (alternativo):** #6f5e4f → #8B4513 → #5a4a3a +### Colores de Botones +- **Botón primario:** #3E352E (Marrón elegante) - reemplaza --deep-earth +- **Botón secundario:** Gradiente --bone-white → --soft-cream +- **Tarjetas featured:** #3E352E (Marrón elegante) +- **Hover effects:** #3E352E/90 (90% opacidad) + ### Fondos de Secciones - **Hero:** #F5F5DC (Bone White) - **Services:** #F5F5DC diff --git a/DEPLOYMENT_README.md b/DEPLOYMENT_README.md index b879e7b..72aa739 100644 --- a/DEPLOYMENT_README.md +++ b/DEPLOYMENT_README.md @@ -25,6 +25,16 @@ NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJxxxxx SUPABASE_SERVICE_ROLE_KEY=eyJxxxxx RESEND_API_KEY=re_xxxxx NEXT_PUBLIC_APP_URL=https://tu-dominio.com + +# Formbricks (opcional - encuestas) +NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=your-environment-id +NEXT_PUBLIC_FORMBRICKS_API_HOST=https://app.formbricks.com + +# Optional: Redis para caching +REDIS_URL=redis://redis:6379 + +# Optional: Analytics +NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX ``` ### 3. **SSL Certificates** @@ -165,6 +175,83 @@ docker-compose -f docker-compose.prod.yml restart - Query optimization - Redis caching (opcional) +## 📝 **Formbricks Integration** + +### **Configuración de Encuestas** +```bash +# Activar Formbricks para recolección de feedback +NEXT_PUBLIC_FORMBRICKS_ENVIRONMENT_ID=clxxxxxxxx +NEXT_PUBLIC_FORMBRICKS_API_HOST=https://app.formbricks.com +``` + +### **Webhooks** +```bash +# Endpoints de webhook para formularios +# Test: https://flows.soul23.cloud/webhook-test/4YZ7RPfo1GT +# Prod: https://flows.soul23.cloud/webhook/4YZ7RPfo1GT + +# Formularios que envían a webhooks: +# - contact (Contacto) +# - franchise (Franquicias) +# - membership (Membresías) + +# Payload structure: +{ + "form": "contact|franchise|membership", + "timestamp_utc": "ISO-8601", + "device_type": "mobile|desktop|unknown", + "...": "campos específicos del formulario" +} +``` + +### **Form Types y Campos** + +**Contact (contacto)** +```json +{ + "form": "contact", + "nombre": "string", + "email": "string", + "telefono": "string", + "motivo": "cita|membresia|franquicia|servicios|pago|resena|otro", + "mensaje": "string", + "timestamp_utc": "string", + "device_type": "string" +} +``` + +**Franchise (franquicias)** +```json +{ + "form": "franchise", + "nombre": "string", + "email": "string", + "telefono": "string", + "ciudad": "string", + "estado": "string", + "socios": "number", + "experiencia_sector": "string", + "experiencia_belleza": "boolean", + "mensaje": "string", + "timestamp_utc": "string", + "device_type": "string" +} +``` + +**Membership (membresías)** +```json +{ + "form": "membership", + "membership_id": "gold|black|vip", + "nombre": "string", + "email": "string", + "telefono": "string", + "mensaje": "string", + "timestamp_utc": "string", + "device_type": "string" +} +``` + ## 🔒 **Seguridad** - SSL/TLS 1.2+ diff --git a/Dockerfile b/Dockerfile index be87147..89d0e12 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,14 @@ # Dockerfile optimizado para Next.js production FROM node:18-alpine AS base -# Instalar dependencias solo para producción +# Instalar dependencias para build FROM base AS deps RUN apk add --no-cache libc6-compat WORKDIR /app # Copiar archivos de dependencias COPY package.json package-lock.json ./ -RUN npm ci --only=production --ignore-scripts && npm cache clean --force +RUN npm ci --ignore-scripts && npm cache clean --force # Build stage FROM base AS builder diff --git a/app/servicios/page.tsx b/app/servicios/page.tsx index 3395916..0638e0a 100644 --- a/app/servicios/page.tsx +++ b/app/servicios/page.tsx @@ -1,14 +1,10 @@ -import { AnimatedLogo } from '@/components/animated-logo' -import { RollingPhrases } from '@/components/rolling-phrases' - -/** @description Services page with home page style structure */ 'use client' +import { useState, useEffect } from 'react' import { AnimatedLogo } from '@/components/animated-logo' import { RollingPhrases } from '@/components/rolling-phrases' /** @description Services page with home page style structure */ -import { useState, useEffect } from 'react' interface Service { id: string diff --git a/components/loading-screen.tsx b/components/loading-screen.tsx index 253e206..3bdc5b0 100644 --- a/components/loading-screen.tsx +++ b/components/loading-screen.tsx @@ -1,7 +1,6 @@ 'use client' import React, { useState, useEffect } from 'react' -import { AnimatedLogo } from './animated-logo' /** @description Elegant loading screen with Anchor 23 branding */ export function LoadingScreen({ onComplete }: { onComplete: () => void }) { @@ -15,18 +14,18 @@ export function LoadingScreen({ onComplete }: { onComplete: () => void }) { setProgress(prev => { if (prev >= 100) { clearInterval(progressInterval) - // Start fade out from top + // Start fade out from center setIsFadingOut(true) // Complete after fade out animation - setTimeout(() => onComplete(), 800) + setTimeout(() => onComplete(), 1000) return 100 } return prev + Math.random() * 12 + 8 // Faster progress }) }, 120) // Faster interval - // Show logo immediately (fast fade in) - setShowLogo(true) + // Show logo with delay for fade in effect + setTimeout(() => setShowLogo(true), 200) return () => { clearInterval(progressInterval) @@ -38,18 +37,31 @@ export function LoadingScreen({ onComplete }: { onComplete: () => void }) {