Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ashcroft08/provesa-web/llms.txt
Use this file to discover all available pages before exploring further.
The Sugerencias Service manages customer suggestions and feedback submissions, including configurable suggestion types and read status tracking.
Overview
This service handles the complete lifecycle of customer suggestions: creation, retrieval, marking as read, and deletion. It also manages the configuration of suggestion types displayed in the dropdown.
Dependencies
sugerenciasRepository - Database operations for suggestions
Methods
getAll()
Retrieves all customer suggestions.
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
const sugerencias = await sugerenciasService.getAll();
Array of suggestion objects:
id: Suggestion identifier
tipo: Type/category of suggestion
nombre: Customer name
mensaje: Suggestion message/content
leida: Boolean indicating if read
createdAt: Timestamp of creation
Example Response
[
{
id: 1,
tipo: 'Mejora del Servicio',
nombre: 'Juan Pérez',
mensaje: 'Sugerencia para mejorar la atención...',
leida: false,
createdAt: '2024-03-12T10:30:00Z'
},
{
id: 2,
tipo: 'Producto Nuevo',
nombre: 'María González',
mensaje: 'Podrían agregar cemento especial...',
leida: true,
createdAt: '2024-03-11T15:20:00Z'
}
]
Implementation Details
Source: src/lib/server/services/sugerencias.service.js:5-7
create()
Creates a new customer suggestion.
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
await sugerenciasService.create({
tipo: 'Mejora del Servicio',
nombre: 'Carlos Rodríguez',
mensaje: 'Sería genial si pudieran ofrecer entrega los sábados'
});
Type or category of suggestion (from configured options)
Suggestion message or feedback content
New suggestions are created with leida: false by default.
Implementation Details
Source: src/lib/server/services/sugerencias.service.js:10-12
markAsRead()
Marks a suggestion as read.
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
await sugerenciasService.markAsRead(1);
Suggestion ID to mark as read
This sets leida: true for the specified suggestion.
Implementation Details
Source: src/lib/server/services/sugerencias.service.js:15-17
delete()
Deletes a suggestion by ID.
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
await sugerenciasService.delete(1);
Implementation Details
Source: src/lib/server/services/sugerencias.service.js:20-22
getConfig()
Retrieves the configuration for suggestion types.
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
const config = await sugerenciasService.getConfig();
Configuration object containing:
opciones: Array of suggestion type strings
Example Response
{
opciones: [
'Mejora del Servicio',
'Producto Nuevo',
'Queja',
'Felicitación',
'Otro'
]
}
Implementation Details
Source: src/lib/server/services/sugerencias.service.js:25-27
updateConfig()
Updates the suggestion type options with JSON parsing.
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
await sugerenciasService.updateConfig([
'Mejora del Servicio',
'Producto Nuevo',
'Sucursal Nueva',
'Queja',
'Felicitación'
]);
// Or with JSON string
await sugerenciasService.updateConfig(
JSON.stringify(['Opción 1', 'Opción 2'])
);
Array of suggestion type strings or JSON string
JSON Parsing
The service automatically handles both formats:
const parsed = typeof opciones === 'string' ? JSON.parse(opciones) : opciones;
Implementation Details
Source: src/lib/server/services/sugerencias.service.js:30-33
Usage Examples
// src/routes/sugerencias/+page.server.js
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
import { fail } from '@sveltejs/kit';
export async function load() {
const config = await sugerenciasService.getConfig();
return { tiposSugerencia: config.opciones };
}
export const actions = {
submit: async ({ request }) => {
const formData = await request.formData();
const tipo = formData.get('tipo');
const nombre = formData.get('nombre');
const mensaje = formData.get('mensaje');
// Validation
if (!tipo || !nombre || !mensaje) {
return fail(400, { error: 'Todos los campos son requeridos' });
}
if (mensaje.length < 10) {
return fail(400, { error: 'El mensaje debe tener al menos 10 caracteres' });
}
try {
await sugerenciasService.create({ tipo, nombre, mensaje });
return { success: true };
} catch (error) {
return fail(500, { error: 'Error al enviar sugerencia' });
}
}
};
<!-- src/routes/sugerencias/+page.svelte -->
<script>
import { enhance } from '$app/forms';
export let data;
export let form;
</script>
<form method="POST" action="?/submit" use:enhance>
<h1>Envíanos tu Sugerencia</h1>
<div>
<label for="nombre">Tu Nombre</label>
<input
type="text"
id="nombre"
name="nombre"
required
/>
</div>
<div>
<label for="tipo">Tipo de Sugerencia</label>
<select id="tipo" name="tipo" required>
<option value="">Selecciona un tipo</option>
{#each data.tiposSugerencia as tipo}
<option value="{tipo}">{tipo}</option>
{/each}
</select>
</div>
<div>
<label for="mensaje">Tu Mensaje</label>
<textarea
id="mensaje"
name="mensaje"
rows="6"
required
minlength="10"
></textarea>
</div>
<button type="submit">Enviar Sugerencia</button>
{#if form?.success}
<p class="success">¡Gracias! Tu sugerencia ha sido enviada.</p>
{/if}
{#if form?.error}
<p class="error">{form.error}</p>
{/if}
</form>
Admin Dashboard
// src/routes/admin/sugerencias/+page.server.js
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
import { fail } from '@sveltejs/kit';
export async function load() {
const [sugerencias, config] = await Promise.all([
sugerenciasService.getAll(),
sugerenciasService.getConfig()
]);
return {
sugerencias,
tiposConfig: config.opciones
};
}
export const actions = {
markRead: async ({ request }) => {
const formData = await request.formData();
const id = parseInt(formData.get('id'));
try {
await sugerenciasService.markAsRead(id);
return { success: true };
} catch (error) {
return fail(500, { error: error.message });
}
},
delete: async ({ request }) => {
const formData = await request.formData();
const id = parseInt(formData.get('id'));
try {
await sugerenciasService.delete(id);
return { success: true };
} catch (error) {
return fail(500, { error: error.message });
}
},
updateConfig: async ({ request }) => {
const formData = await request.formData();
const opciones = formData.get('opciones'); // JSON string
try {
await sugerenciasService.updateConfig(opciones);
return { success: true };
} catch (error) {
return fail(500, { error: error.message });
}
}
};
<!-- src/routes/admin/sugerencias/+page.svelte -->
<script>
export let data;
$: unreadCount = data.sugerencias.filter(s => !s.leida).length;
</script>
<div class="admin-sugerencias">
<header>
<h1>Sugerencias de Clientes</h1>
<span class="badge">{unreadCount} sin leer</span>
</header>
<div class="sugerencias-list">
{#each data.sugerencias as sugerencia (sugerencia.id)}
<div class="sugerencia" class:unread={!sugerencia.leida}>
<div class="header">
<span class="tipo">{sugerencia.tipo}</span>
<span class="date">
{new Date(sugerencia.createdAt).toLocaleDateString()}
</span>
</div>
<h3>{sugerencia.nombre}</h3>
<p>{sugerencia.mensaje}</p>
<div class="actions">
{#if !sugerencia.leida}
<form method="POST" action="?/markRead">
<input type="hidden" name="id" value="{sugerencia.id}" />
<button type="submit">Marcar como Leída</button>
</form>
{/if}
<form method="POST" action="?/delete">
<input type="hidden" name="id" value="{sugerencia.id}" />
<button type="submit" class="delete">Eliminar</button>
</form>
</div>
</div>
{/each}
</div>
</div>
Data Structure
Sugerencia Object
interface Sugerencia {
id: number;
tipo: string;
nombre: string;
mensaje: string;
leida: boolean;
createdAt: string; // ISO timestamp
}
Config Object
interface SugerenciasConfig {
opciones: string[];
}
Default Suggestion Types
Common suggestion type options:
const defaultOptions = [
'Mejora del Servicio',
'Producto Nuevo',
'Queja',
'Felicitación',
'Sucursal Nueva',
'Horario de Atención',
'Otro'
];
await sugerenciasService.updateConfig(defaultOptions);
Filtering and Sorting
Get Unread Suggestions
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
const allSugerencias = await sugerenciasService.getAll();
const unread = allSugerencias.filter(s => !s.leida);
const read = allSugerencias.filter(s => s.leida);
Sort by Date
const sorted = allSugerencias.sort((a, b) =>
new Date(b.createdAt) - new Date(a.createdAt)
);
Filter by Type
const quejas = allSugerencias.filter(s => s.tipo === 'Queja');
const mejoras = allSugerencias.filter(s => s.tipo === 'Mejora del Servicio');
Best Practices
Display unread count prominently in admin dashboard for quick visibility.
Validate and sanitize user input before creating suggestions to prevent XSS attacks.
Limit suggestion types to 5-7 options for better user experience.
Consider implementing email notifications for new suggestions.
Email Notification Example
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
import { sendEmail } from '$lib/server/email';
async function createSugerenciaWithNotification(data) {
// Create suggestion
await sugerenciasService.create(data);
// Send notification email
await sendEmail({
to: 'admin@provesa.com',
subject: `Nueva Sugerencia: ${data.tipo}`,
html: `
<h2>Nueva Sugerencia Recibida</h2>
<p><strong>Tipo:</strong> ${data.tipo}</p>
<p><strong>Nombre:</strong> ${data.nombre}</p>
<p><strong>Mensaje:</strong></p>
<p>${data.mensaje}</p>
`
});
}
Statistics and Analytics
import { sugerenciasService } from '$lib/server/services/sugerencias.service.js';
async function getSugerenciasStats() {
const sugerencias = await sugerenciasService.getAll();
const stats = {
total: sugerencias.length,
unread: sugerencias.filter(s => !s.leida).length,
byType: {}
};
// Count by type
sugerencias.forEach(s => {
stats.byType[s.tipo] = (stats.byType[s.tipo] || 0) + 1;
});
// Most common type
stats.mostCommon = Object.entries(stats.byType)
.sort(([,a], [,b]) => b - a)[0]?.[0];
return stats;
}
Validation Helpers
function validateSugerencia(data) {
const errors = [];
if (!data.tipo || data.tipo.trim().length === 0) {
errors.push('Tipo es requerido');
}
if (!data.nombre || data.nombre.trim().length < 2) {
errors.push('Nombre debe tener al menos 2 caracteres');
}
if (!data.mensaje || data.mensaje.trim().length < 10) {
errors.push('Mensaje debe tener al menos 10 caracteres');
}
if (data.mensaje && data.mensaje.length > 1000) {
errors.push('Mensaje no puede exceder 1000 caracteres');
}
return errors;
}
// Usage
const errors = validateSugerencia(formData);
if (errors.length > 0) {
return fail(400, { errors });
}