Initial commit
This commit is contained in:
124
frontend-client/src/lib/components/TicketCard.svelte
Normal file
124
frontend-client/src/lib/components/TicketCard.svelte
Normal file
@@ -0,0 +1,124 @@
|
||||
<script lang="ts">
|
||||
export let ticket: import('$lib/stores/tickets').Ticket;
|
||||
|
||||
// Status mapping
|
||||
const statusConfig = {
|
||||
NEW: { label: 'Nuevo', class: 'badge-new' },
|
||||
IN_PROGRESS: { label: 'En Progreso', class: 'badge-in-progress' },
|
||||
WAITING_FOR_CLIENT: { label: 'Esperando Cliente', class: 'badge-waiting' },
|
||||
RESOLVED: { label: 'Resuelto', class: 'badge-resolved' },
|
||||
CLOSED: { label: 'Cerrado', class: 'badge-closed' },
|
||||
REOPENED: { label: 'Reabierto', class: 'badge-reopened' }
|
||||
};
|
||||
|
||||
// Priority mapping
|
||||
const priorityConfig = {
|
||||
LOW: { label: 'Baja', class: 'badge-priority-low' },
|
||||
MEDIUM: { label: 'Media', class: 'badge-priority-medium' },
|
||||
HIGH: { label: 'Alta', class: 'badge-priority-high' },
|
||||
URGENT: { label: 'Urgente', class: 'badge-priority-urgent' }
|
||||
};
|
||||
|
||||
// Format date
|
||||
function formatDate(dateString: string): string {
|
||||
return new Date(dateString).toLocaleDateString('es-ES', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
}
|
||||
|
||||
// Format relative time
|
||||
function formatRelativeTime(dateString: string): string {
|
||||
const date = new Date(dateString);
|
||||
const now = new Date();
|
||||
const diffInMinutes = Math.floor((now.getTime() - date.getTime()) / (1000 * 60));
|
||||
|
||||
if (diffInMinutes < 1) return 'hace un momento';
|
||||
if (diffInMinutes < 60) return `hace ${diffInMinutes}m`;
|
||||
|
||||
const diffInHours = Math.floor(diffInMinutes / 60);
|
||||
if (diffInHours < 24) return `hace ${diffInHours}h`;
|
||||
|
||||
const diffInDays = Math.floor(diffInHours / 24);
|
||||
if (diffInDays < 7) return `hace ${diffInDays}d`;
|
||||
|
||||
return formatDate(dateString);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="card hover:shadow-md transition-shadow">
|
||||
<div class="card-content">
|
||||
<div class="flex justify-between items-start mb-3">
|
||||
<h3 class="text-lg font-medium text-gray-900 line-clamp-2">
|
||||
<a href="/tickets/{ticket.id}" class="hover:text-primary-600">
|
||||
{ticket.title}
|
||||
</a>
|
||||
</h3>
|
||||
<div class="flex items-center space-x-2 ml-4">
|
||||
<span class={`${statusConfig[ticket.status].class}`}>
|
||||
{statusConfig[ticket.status].label}
|
||||
</span>
|
||||
<span class={`${priorityConfig[ticket.priority].class}`}>
|
||||
{priorityConfig[ticket.priority].label}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 text-sm line-clamp-3 mb-4">
|
||||
{ticket.description}
|
||||
</p>
|
||||
|
||||
<div class="flex justify-between items-center text-xs text-gray-500">
|
||||
<div class="flex items-center space-x-4">
|
||||
<span>#{ticket.id.substring(0, 8)}</span>
|
||||
{#if ticket.category_name}
|
||||
<span class="bg-gray-100 text-gray-600 px-2 py-1 rounded">
|
||||
{ticket.category_name}
|
||||
</span>
|
||||
{/if}
|
||||
{#if ticket.assigned_to_name}
|
||||
<span class="flex items-center space-x-1">
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
<span>{ticket.assigned_to_name}</span>
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex items-center space-x-3">
|
||||
{#if ticket.due_date}
|
||||
<span class="flex items-center space-x-1 {new Date(ticket.due_date) < new Date() ? 'text-red-600' : ''}">
|
||||
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<span>Vence {formatRelativeTime(ticket.due_date)}</span>
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<span title={formatDate(ticket.updated_at)}>
|
||||
Actualizado {formatRelativeTime(ticket.updated_at)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.line-clamp-2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.line-clamp-3 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user