### Component Test Example (React/TypeScript)
Source: https://github.com/sanchezx1/v0-fullcolor-cotizador/blob/main/docs/agents/testing.md
Provides an example of component testing using Testing Library for React components. It renders a ProductCard component and asserts that the product name is present in the document. This ensures UI components render correctly with their props.
```typescript
// tests/unit/product-card.test.tsx
import { render, screen } from '@testing-library/react'
import { ProductCard } from '@/components/product-card'
describe('ProductCard', () => {
test('debe mostrar nombre del producto', () => {
render()
expect(screen.getByText('Tarjetas de Presentación')).toBeInTheDocument()
})
})
```
--------------------------------
### Environment Configuration (.env) Example
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Shows example environment variables for a project, differentiating between client-side (public) and server-side (private) configurations. Includes settings for Supabase, SendGrid API key, email addresses, and other application-specific constants.
```bash
# Client-side (Public)
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
# Server-side (Private)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SENDGRID_API_KEY=SG.xxxxxxxxxxxxx
FROM_EMAIL=noreply@fullcolor.ec
FROM_NAME=FullColor
ADMIN_EMAIL=admin@fullcolor.ec
REVALIDATE_SECRET=your-secret-key-here
FULLCOLOR_LOGO_URL=https://your-domain.com/logo.png
```
--------------------------------
### E2E Test Example (Playwright)
Source: https://github.com/sanchezx1/v0-fullcolor-cotizador/blob/main/docs/agents/testing.md
Illustrates an end-to-end test scenario using Playwright. This test simulates user interaction by navigating to a page, filling a form, clicking a button, and asserting that an element in the cart updates. It verifies the complete user flow.
```typescript
// e2e/specs/nuevo-flujo.spec.ts
import { test, expect } from '@playwright/test'
test('usuario puede agregar producto al cotizador', async ({ page }) => {
await page.goto('/catalogo')
await page.click('text=Tarjetas de Presentación')
await page.fill('input[name="cantidad"]', '500')
await page.click('button:has-text("Agregar al Cotizador")')
await expect(page.locator('.cotizador-badge')).toContainText('1')
})
```
--------------------------------
### Unit Test Example (TypeScript)
Source: https://github.com/sanchezx1/v0-fullcolor-cotizador/blob/main/docs/agents/testing.md
Demonstrates how to write unit tests for validation functions using Jest. It includes a basic test case for email validation, showing expected true and false outcomes. This helps ensure the reliability of utility functions.
```typescript
// tests/unit/nueva-validacion.test.ts
import { validarEmail } from '@/src/lib/validations'
describe('validarEmail', () => {
test('debe aceptar email válido', () => {
expect(validarEmail('user@example.com')).toBe(true)
})
test('debe rechazar email sin @', () => {
expect(validarEmail('userexample.com')).toBe(false)
})
})
```
--------------------------------
### Bash Command for Unit Tests
Source: https://github.com/sanchezx1/v0-fullcolor-cotizador/blob/main/docs/agents/testing.md
Shows the command to execute specific unit tests using npm scripts. This allows developers to run a targeted set of tests, improving feedback loops during development. The `-- nueva-validacion.test.ts` argument specifies which test file to run.
```bash
npm run test:unit -- nueva-validacion.test.ts
```
--------------------------------
### Bash Command for E2E UI Tests
Source: https://github.com/sanchezx1/v0-fullcolor-cotizador/blob/main/docs/agents/testing.md
Demonstrates the command to run end-to-end UI tests with Playwright via npm scripts. This command targets a specific spec file for execution, useful for debugging or running isolated E2E test suites.
```bash
npm run test:e2e:ui -- nuevo-flujo.spec.ts
```
--------------------------------
### Get Product with Pricing Tiers (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Fetches a specific product along with its associated pricing tiers. This allows for detailed inspection of how pricing changes based on quantity. The function returns the product name and an array of pricing tiers, each specifying a minimum quantity and the corresponding unit price.
```typescript
import { getProductWithTiers } from '@/src/lib/data'
const product = await getProductWithTiers(123)
if (product) {
console.log(`Product: ${product.nombre}`)
console.log(`Pricing tiers:`)
product.pricingTiers.forEach(tier => {
console.log(` ${tier.cantidad_min}+ units: $${tier.precio_unitario}`)
})
}
// Response structure:
// {
// id: 123,
// nombre: "Tarjetas Premium",
// categoria: "Papelería Corporativa",
// pricingTiers: [
// { id: 1, producto_id: 123, cantidad_min: 100, precio_unitario: 0.50 },
// { id: 2, producto_id: 123, cantidad_min: 500, precio_unitario: 0.40 },
// { id: 3, producto_id: 123, cantidad_min: 1000, precio_unitario: 0.30 }
// ]
// }
```
--------------------------------
### Revalidate Cache via API Endpoint (Bash)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
These curl commands trigger cache revalidation on a Next.js API route, supporting GET or POST methods with authorization header. It depends on the /api/revalidate endpoint and a secret token. Inputs: HTTP method and bearer token; outputs: JSON response with success message and timestamp. Limitations: Requires valid secret; no additional parameters for specific paths.
```bash
# GET request
curl -X GET "https://your-domain.com/api/revalidate" \
-H "Authorization: Bearer YOUR_REVALIDATE_SECRET"
# POST request
curl -X POST "https://your-domain.com/api/revalidate" \
-H "Authorization: Bearer YOUR_REVALIDATE_SECRET"
# Response:
# {
# "success": true,
# "message": "Cache revalidated successfully",
# "timestamp": "2025-01-15T10:30:00.000Z"
# }
```
--------------------------------
### Create Lead with Duplicate Detection (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Creates a new lead entry in the system while incorporating logic to detect and handle potential duplicates based on email address. If a lead with the same email already exists, it throws a specific error, providing details of both the existing and new lead data. This prevents redundant entries and allows for informed user actions.
```typescript
import { crearLead } from '@/src/services/quotes'
try {
const lead = await crearLead({
nombre: "Juan Pérez",
email: "juan@empresa.com",
telefono: "+593 99 123 4567",
empresa: "Mi Empresa S.A.",
ruc_cedula: "1234567890123",
ciudad: "Quito"
})
console.log(`Lead created with ID: ${lead.id}`)
} catch (error) {
if (error.code === 'LEAD_EMAIL_EXISTS') {
// Handle duplicate email
console.log('Lead already exists:', error.existingLead)
console.log('New data:', error.newData)
// UI should prompt user to update or use existing
} else {
console.error('Error creating lead:', error.message)
}
}
```
--------------------------------
### Search Products by Term (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Enables searching for products based on a given term, which can match against the product's name, description, or category. It returns an array of matching products, displaying their names and categories. This is useful for implementing search functionality within the platform.
```typescript
import { searchProducts } from '@/src/lib/data'
// Search by name, description, or category
const results = await searchProducts('tarjetas')
console.log(`Found ${results.length} products`)
results.forEach(p => console.log(`- ${p.nombre} (${p.categoria})`))
```
--------------------------------
### Download PDF from Supabase Storage with TypeScript
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Demonstrates how to retrieve a PDF file from a Supabase storage bucket named 'cotizaciones'. It shows two methods: obtaining the public URL for direct access and downloading the file as a Blob, which can then be used to open the PDF in a new browser tab.
```typescript
import { supabase } from '@/src/services/supabaseClient'
// Get PDF URL
const { data: urlData } = supabase.storage
.from('cotizaciones')
.getPublicUrl('cotizacion-456-1704801234567.pdf')
console.log('PDF URL:', urlData.publicUrl)
// Or download directly
const { data: blob, error } = await supabase.storage
.from('cotizaciones')
.download('cotizacion-456-1704801234567.pdf')
if (blob) {
const url = URL.createObjectURL(blob)
window.open(url, '_blank')
}
```
--------------------------------
### Query Active Products by Category with Supabase (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
This snippet queries active products in a specific category from the 'productos' table using the Supabase client, ordering by name. It depends on the supabaseClient import. Inputs: Filters for activo=true and categoria='Papelería Corporativa'; outputs: Array of product data or error. Limitations: Basic error handling; no pagination for large datasets.
```typescript
import { supabase } from '@/src/services/supabaseClient'
const { data: products, error } = await supabase
.from('productos')
.select('*')
.eq('activo', true)
.eq('categoria', 'Papelería Corporativa')
.order('nombre', { ascending: true })
if (error) {
console.error('Error:', error)
} else {
console.log(`Found ${products.length} products`)
}
```
--------------------------------
### Upload Product Image to Supabase Storage with TypeScript
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Handles uploading a product image to a Supabase storage bucket named 'productos'. It generates a unique file name, uploads the image with JPEG content type, and upon success, retrieves the public URL to update a product record in the 'productos' table.
```typescript
import { supabase } from '@/src/services/supabaseClient'
// Upload image to productos bucket
const file = event.target.files[0]
const fileName = `product-${Date.now()}.jpg`
const { data, error } = await supabase.storage
.from('productos')
.upload(fileName, file, {
contentType: 'image/jpeg',
upsert: false
})
if (error) {
console.error('Upload error:', error)
} else {
// Get public URL
const { data: urlData } = supabase.storage
.from('productos')
.getPublicUrl(fileName)
console.log('Image URL:', urlData.publicUrl)
// Update product with image URL
await supabase
.from('productos')
.update({ imagen_url: urlData.publicUrl })
.eq('id', productId)
}
```
--------------------------------
### Handle User Login Flow with Supabase Auth (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
This client-side component manages email/password login using Supabase Auth, redirecting to admin on success. It uses Next.js useRouter and a form handler. Inputs: Email and password from form; outputs: Authentication result and navigation. Limitations: Basic error logging; no password recovery or social login.
```typescript
'use client'
import { supabase } from '@/src/services/supabaseClient'
import { useRouter } from 'next/navigation'
export default function LoginPage() {
const router = useRouter()
const handleLogin = async (email: string, password: string) => {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password
})
if (error) {
console.error('Login error:', error.message)
} else {
router.push('/admin')
}
}
return (
)
}
```
--------------------------------
### Fetch Top Quoted Products using Dashboard Service (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
This snippet retrieves the top N most quoted products from the dashboard service and logs their details including name, SKU, quote count, total units, and generated revenue. It depends on the imported dashboardService module which handles backend API calls. Inputs include the number of products to fetch (default 10); outputs are an array of product objects for logging or further processing. Limitations: Assumes service is properly configured; error handling is not shown.
```typescript
import { getProductosTopCotizados } from '@/src/services/admin/dashboardService'
const topProducts = await getProductosTopCotizados(10)
topProducts.forEach((product, index) => {
console.log(`#${index + 1}: ${product.nombre}`)
console.log(` SKU: ${product.sku}`)
console.log(` Times quoted: ${product.veces_cotizado}`)
console.log(` Total units: ${product.unidades_totales}`)
console.log(` Revenue: $${product.ingresos_generados}`)
})
```
--------------------------------
### List All Active Products with Caching (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Retrieves a list of all active products, utilizing a cache that expires every 5 minutes for performance optimization. The output includes essential product details such as SKU, name, category, minimum order quantity, and stock status. This function is useful for displaying product catalogs.
```typescript
import { listProducts } from '@/src/lib/data'
// Gets all active products (cached for 5 minutes)
const products = await listProducts()
products.forEach(product => {
console.log(`${product.sku} - ${product.nombre}`)
console.log(`Category: ${product.categoria}`)
console.log(`Min order: ${product.minimo_pedido}`)
console.log(`Active: ${product.activo}, Out of stock: ${product.agotado}`)
})
```
--------------------------------
### PDF Generation and Email Services
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
PDF quote generation using Supabase edge functions with automatic email delivery. The generate-pdf function creates PDFs and sends them to clients, while send-email allows manual email sending with optional recipient override. Includes PDF existence checking and URL retrieval services for quote management.
```TypeScript
import { supabase } from '@/src/services/supabaseClient'
const { data, error } = await supabase.functions.invoke('generate-pdf', {
body: { quoteId: 456 }
})
if (error) {
console.error('Error generating PDF:', error)
} else {
console.log('PDF generated:', data.pdfUrl)
console.log('Email sent:', data.emailSent)
console.log('Recipient:', data.emailRecipient)
console.log('File name:', data.fileName)
}
// Response structure:
// {
// success: true,
// pdfUrl: "https://...storage.supabase.co/.../cotizacion-456.pdf",
// fileName: "cotizacion-456-1704801234567.pdf",
// quoteId: 456,
// emailSent: true,
// emailRecipient: "cliente@empresa.com",
// emailError: null
// }
```
```TypeScript
import { supabase } from '@/src/services/supabaseClient'
const { data, error } = await supabase.functions.invoke('send-email', {
body: {
quoteId: 456,
recipientEmail: 'cliente@empresa.com' // Optional override
}
})
if (data?.success) {
console.log(`Email sent to: ${data.recipient}`)
console.log(`Quote number: ${data.cotizacionNumero}`)
}
```
```TypeScript
import { pdfGenerationService } from '@/src/services/pdfGenerationService'
// Generate new PDF
const result = await pdfGenerationService.generateQuotePDF(456)
if (result.success) {
console.log('PDF URL:', result.pdfUrl)
console.log('Email sent:', result.emailSent)
} else {
console.error('Error:', result.error)
}
// Check if PDF exists
const hasPDF = await pdfGenerationService.hasExistingPDF(456)
console.log('PDF exists:', hasPDF)
// Get existing PDF URL
const pdfUrl = await pdfGenerationService.getExistingPDFUrl(456)
if (pdfUrl) {
console.log('Existing PDF:', pdfUrl)
}
```
--------------------------------
### Unit Test for Price Calculation Logic with TypeScript
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
A unit test suite for the `priceForQuantity` function using Jest. It defines pricing tiers and verifies that the function correctly calculates the price per unit and subtotal based on quantity, and handles cases where the quantity does not fall into any defined tier.
```typescript
import { priceForQuantity } from '@/src/lib/data'
describe('priceForQuantity', () => {
const tiers = [
{ minQty: 100, maxQty: 499, pricePerUnit: 0.50 },
{ minQty: 500, maxQty: 999, pricePerUnit: 0.40 },
{ minQty: 1000, maxQty: null, pricePerUnit: 0.30 }
]
test('applies correct tier for 750 units', () => {
const result = priceForQuantity(tiers, 750)
expect(result.isValid).toBe(true)
expect(result.pricePerUnit).toBe(0.40)
expect(result.subtotal).toBe(300.00)
expect(result.appliedTier.minQty).toBe(500)
})
test('returns invalid for 50 units', () => {
const result = priceForQuantity(tiers, 50)
expect(result.isValid).toBe(false)
expect(result.pricePerUnit).toBeNull()
})
})
```
--------------------------------
### Product CRUD Operations
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Complete product lifecycle management including creation with auto-generated SKU, pricing tier configuration, listing with filters, updates, and deletion. The createProducto function auto-generates SKUs based on category codes (e.g., PAP-042 for Papelería Corporativa). Requires valid product data including nombre, categoria, descripcion, unidad, minimo_pedido, and activo status.
```TypeScript
import { createProducto } from '@/src/services/admin/productService'
const product = await createProducto({
nombre: "Tarjetas de presentación Premium",
categoria: "Papelería Corporativa",
descripcion: "Tarjetas con acabado UV brillante",
unidad: "unidad",
minimo_pedido: 100,
activo: true
// SKU will be auto-generated based on category: "PAP-042"
})
console.log(`Product created with SKU: ${product.sku}`)
console.log(`Product ID: ${product.id}`)
```
```TypeScript
import { addPrecioEscalonado } from '@/src/services/admin/productService'
// Add multiple pricing tiers
await addPrecioEscalonado(product.id, {
cantidad_min: 100,
precio_unitario: 0.50
})
await addPrecioEscalonado(product.id, {
cantidad_min: 500,
precio_unitario: 0.40
})
await addPrecioEscalonado(product.id, {
cantidad_min: 1000,
precio_unitario: 0.30
})
console.log('Pricing tiers added successfully')
```
```TypeScript
import { getProductos } from '@/src/services/admin/productService'
const result = await getProductos({
busqueda: 'tarjetas',
categoria: 'Papelería Corporativa',
estado: 'activos',
page: 1,
perPage: 20
})
console.log(`Found ${result.total} products`)
console.log(`Page ${result.page} of ${result.totalPages}`)
result.data.forEach(product => {
console.log(`${product.sku} - ${product.nombre}`)
})
// Response structure:
// {
// data: [...products...],
// total: 45,
// page: 1,
// perPage: 20,
// totalPages: 3
// }
```
```TypeScript
import { updateProducto } from '@/src/services/admin/productService'
const updated = await updateProducto(123, {
nombre: "Tarjetas Premium Actualizado",
descripcion: "Nueva descripción",
activo: true,
agotado: false
})
console.log('Product updated:', updated.nombre)
```
```TypeScript
import { deleteProducto } from '@/src/services/admin/productService'
await deleteProducto(123)
console.log('Product deleted successfully')
```
--------------------------------
### E2E Test for Quote Creation Flow with Playwright
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
An end-to-end test for the quote creation process using Playwright. It simulates user interactions including navigating to the homepage, adding a product with a specified quantity, filling out a contact form, submitting the quote, and verifying successful redirection and confirmation message.
```typescript
import { test, expect } from '@playwright/test'
test('complete quote creation flow', async ({ page }) => {
await page.goto('/')
// Add product to quote
await page.click('[data-testid="product-123"]')
await page.fill('[data-testid="quantity-input"]', '500')
await page.click('[data-testid="add-to-quote"]')
// Fill contact form
await page.fill('[name="email"]', 'test@example.com')
await page.fill('[name="nombre"]', 'Test User')
await page.fill('[name="telefono"]', '+593 99 123 4567')
// Submit quote
await page.click('[data-testid="submit-quote"]')
// Verify success
await expect(page).toHaveURL(//confirmacion/)
await expect(page.locator('text=Cotización enviada')).toBeVisible()
})
```
--------------------------------
### Create Complete Quotation with Items (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Generates a new quotation, including all associated line items. This function takes a lead ID, an array of items (each with product ID, quantity, price, and subtotal), the sales channel, and any relevant notes. It returns the created quotation details and a list of the created items, serving as the core quotation generation logic.
```typescript
import { crearCotizacion } from '@/src/services/quotes'
const { cotizacion, items } = await crearCotizacion({
leadId: 123,
items: [
{
productoId: 1,
cantidad: 500,
precioUnitario: 0.40,
subtotal: 200.00
},
{
productoId: 2,
cantidad: 1000,
precioUnitario: 0.30,
subtotal: 300.00
}
],
canal: 'web',
notas: 'Entrega urgente en Quito'
})
console.log(`Quote created: ${cotizacion.numero}`)
console.log(`Status: ${cotizacion.estado}`)
console.log(`Total: $${cotizacion.total}`)
console.log(`Items created: ${items.length}`)
// Response structure:
// cotizacion: {
// id: 456,
// lead_id: 123,
// numero: "COT-00456",
// estado: "pendiente",
// total: 500.00,
// validez_dias: 30,
// canal: "web",
// created_at: "2025-01-15T10:30:00Z"
// }
```
--------------------------------
### Implement Protected Admin Route with Supabase Auth (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
This server-side component checks user authentication using Supabase Auth and redirects unauthenticated users to login. It uses Next.js App Router and supabaseClient. Inputs: User's session; outputs: Redirect or rendered admin page. Limitations: Relies on middleware for route protection; no role-based access shown.
```typescript
// middleware.ts automatically protects /admin routes
// User must be authenticated with Supabase Auth
// Access admin page (Next.js App Router)
import { redirect } from 'next/navigation'
import { supabase } from '@/src/services/supabaseClient'
export default async function AdminPage() {
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
redirect('/login')
}
return Admin Dashboard
}
```
--------------------------------
### Insert or Update Lead via Supabase Edge Function (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
This snippet invokes a Supabase Edge Function to upsert a lead, bypassing RLS with service role privileges. It requires the supabaseClient and function deployment. Inputs: Lead object with fields like nombre, email, etc.; outputs: Success status and lead ID if created/updated. Limitations: Function must exist ('upsert-lead'); sensitive data exposure if not secured.
```typescript
import { supabase } from '@/src/services/supabaseClient'
// This bypasses RLS using service role in Edge Function
const { data, error } = await supabase.functions.invoke('upsert-lead', {
body: {
nombre: "Juan Pérez",
email: "juan@empresa.com",
telefono: "+593 99 123 4567",
empresa: "Mi Empresa S.A.",
ruc_cedula: "1234567890123",
ciudad: "Quito"
}
})
if (data.success) {
console.log('Lead created/updated:', data.lead.id)
}
```
--------------------------------
### Query Pending Quotes with Related Leads and Items (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
This code performs a relational query on the 'cotizaciones' table to fetch pending quotes with joined leads and quote items including product details, limited to the latest 10. It uses the Supabase client for nested selects. Inputs: Filter for estado='pendiente'; outputs: Array of quotes with nested objects for logging. Limitations: Relies on proper table relationships; potential performance issues with deep nesting on large data.
```typescript
import { supabase } from '@/src/services/supabaseClient'
const { data: quotes, error } = await supabase
.from('cotizaciones')
.select(`
*,
leads (
nombre,
email,
empresa
),
items_cotizacion (
*,
productos (
nombre,
sku
)
)
`)
.eq('estado', 'pendiente')
.order('created_at', { ascending: false })
.limit(10)
if (data) {
quotes.forEach(quote => {
console.log(`Quote ${quote.numero}`)
console.log(`Lead: ${quote.leads.nombre}`)
console.log(`Items: ${quote.items_cotizacion.length}`)
})
}
```
--------------------------------
### Calculate Price for Product Quantity (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Calculates the price for a specified quantity of a product, considering pricing tiers. It returns detailed pricing information including price per unit, subtotal, applied tier, and product details. Ensure the product ID and quantity are valid.
```typescript
import { calculatePriceForProduct } from '@/src/lib/data'
// Calculate price for 750 units of product ID 123
const result = await calculatePriceForProduct(123, 750)
if (result.isValid) {
console.log(`Price per unit: $${result.pricePerUnit}`)
console.log(`Subtotal: $${result.subtotal}`)
console.log(`Applied tier: ${result.appliedTier.minQty}+ units`)
console.log(`Product: ${result.product.nombre}`)
} else {
console.error('Invalid quantity or no pricing available')
}
// Response structure:
// {
// pricePerUnit: 0.40,
// subtotal: 300.00,
// appliedTier: { minQty: 500, maxQty: 999, pricePerUnit: 0.40 },
// isValid: true,
// product: { id: 123, nombre: "Tarjetas Premium", ... }
// }
```
--------------------------------
### Apply Rate Limiting with TypeScript
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Implements rate limiting for API requests to prevent abuse. It extracts the client's IP address and checks against defined limits (e.g., 20 requests per minute). Returns a 429 status code if the limit is exceeded, indicating the time to retry.
```typescript
import { checkRateLimit } from '@/src/lib/rateLimiter'
export async function POST(request: Request) {
const clientIp = request.headers.get('x-forwarded-for') || 'unknown'
const key = `${clientIp}:POST:/api/quotes`
const { limited, retryAfterSeconds } = checkRateLimit(key, {
limit: 20, // Max requests
windowMs: 60000 // Per minute
})
if (limited) {
return Response.json(
{ error: 'Rate limit exceeded', retryAfter: retryAfterSeconds },
{ status: 429 }
)
}
// Process request...
}
```
--------------------------------
### Report Web Vitals in Next.js
Source: https://github.com/sanchezx1/v0-fullcolor-cotizador/blob/main/docs/agents/performance.md
This code demonstrates how to report Web Vitals metrics to both console and Vercel Analytics. The function can be used to track performance metrics like LCP, FID, and CLS in development and production environments.
```TypeScript
// lib/performance.ts
export function reportWebVitals(metric) {
// Enviar a analytics personalizado
console.log(metric)
// O enviar a Vercel Analytics
if (window.va) {
window.va('event', {
name: metric.name,
value: metric.value,
label: metric.id,
})
}
}
// app/layout.tsx
export { reportWebVitals } from '@/lib/performance'
```
--------------------------------
### Monitor LCP with Performance Observer API
Source: https://github.com/sanchezx1/v0-fullcolor-cotizador/blob/main/docs/agents/performance.md
This React component uses the Performance Observer API to specifically track Largest Contentful Paint (LCP) metrics. It demonstrates client-side performance monitoring in a Next.js application.
```TypeScript
// components/PerformanceMonitor.tsx
'use client'
import { useEffect } from 'react'
export function PerformanceMonitor() {
useEffect(() => {
if (typeof window === 'undefined') return
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'largest-contentful-paint') {
console.log('LCP:', entry.renderTime || entry.loadTime)
}
}
})
observer.observe({ entryTypes: ['largest-contentful-paint'] })
return () => observer.disconnect()
}, [])
return null
}
```
--------------------------------
### Integrate Vercel Analytics in Next.js Layout
Source: https://github.com/sanchezx1/v0-fullcolor-cotizador/blob/main/docs/agents/performance.md
This snippet shows how to integrate Vercel Analytics into a Next.js application layout. The Analytics component should be placed in the root layout to track page views and performance metrics across the entire application.
```TypeScript
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react'
export default function RootLayout({ children }) {
return (
{children}
)
}
```
--------------------------------
### Dashboard Statistics Service
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
Comprehensive dashboard analytics providing quote statistics, revenue estimates, and conversion metrics. Returns detailed analytics including total quotes, monthly performance, conversion rates, and lead tracking. Useful for admin dashboard displays and business intelligence reporting.
```TypeScript
import { getEstadisticasDashboard } from '@/src/services/admin/dashboardService'
const stats = await getEstadisticasDashboard()
console.log(`Total quotes: ${stats.total_cotizaciones}`)
console.log(`Quotes this month: ${stats.cotizaciones_mes}`)
console.log(`Estimated revenue: $${stats.ingresos_estimados}`)
console.log(`Pending quotes: ${stats.cotizaciones_pendiente}`)
console.log(`Sent quotes: ${stats.cotizaciones_enviadas}`)
console.log(`Approved quotes: ${stats.cotizaciones_aprobadas}`)
console.log(`Rejected quotes: ${stats.cotizaciones_rechazadas}`)
// Full response structure:
// {
// total_cotizaciones: 150,
// cotizaciones_mes: 25,
// ingresos_estimados: 45000.00,
// cotizaciones_pendiente: 10,
// cotizaciones_enviadas: 120,
// cotizaciones_aprobadas: 15,
// cotizaciones_rechazadas: 5,
// tasa_conversion: 0.10,
// total_leads: 180
// }
```
--------------------------------
### Fetch Quotes Per Day for Last 7 Days (TypeScript)
Source: https://context7.com/sanchezx1/v0-fullcolor-cotizador/llms.txt
This code fetches the number of quotes per day for the last 7 days using the dashboard service and logs the date and count for each day. It relies on the getCotizacionesPorDia function from the imported service. Inputs: None (defaults to last 7 days); outputs: An array of objects with fecha (date string) and cantidad (quote count). Limitations: No error handling; response format is hardcoded in comments.
```typescript
import { getCotizacionesPorDia } from '@/src/services/admin/dashboardService'
const dailyStats = await getCotizacionesPorDia()
dailyStats.forEach(day => {
console.log(`${day.fecha}: ${day.cantidad} quotes`)
})
// Example response:
// [
// { fecha: "2025-01-15", cantidad: 5 },
// { fecha: "2025-01-14", cantidad: 8 },
// { fecha: "2025-01-13", cantidad: 3 },
// ...
// ]
```
=== COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.