SearchResults.svelte 4.11 KB
<script>
  import { goto } from '$app/navigation';
  import { clearSearch } from '$lib/stores/searchStore';

  let { results = [], query = '', selectedIndex = -1 } = $props();

  function handleSelect(item) {
    if (item.tipo === 'entidad') {
      goto(`/entidad/${item.codigo}`);
    } else if (item.tipo === 'objeto_gasto') {
      goto(`/objeto/${item.codigo}`);
    } else if (item.tipo === 'rubro') {
      goto(`/rubro/${item.codigo}`);
    }
    clearSearch();
  }

  // Agrupar resultados por tipo
  let groupedResults = $derived(() => {
    const entidades = results.filter(r => r.tipo === 'entidad');
    const objetos = results.filter(r => r.tipo === 'objeto_gasto');
    const rubros = results.filter(r => r.tipo === 'rubro');
    return { entidades, objetos, rubros };
  });

  // Calcular índice global para navegación con teclado
  function getGlobalIndex(tipo, localIndex) {
    const g = groupedResults();
    if (tipo === 'entidad') {
      return localIndex;
    } else if (tipo === 'objeto_gasto') {
      return g.entidades.length + localIndex;
    } else {
      return g.entidades.length + g.objetos.length + localIndex;
    }
  }
</script>

{#if results.length > 0}
  <div class="absolute top-full left-0 right-0 mt-1 bg-white border rounded shadow-lg max-h-80 overflow-y-auto z-50">
    {#if groupedResults().entidades.length > 0}
      <div class="px-3 py-1.5 bg-slate-50 border-b">
        <span class="text-xs font-medium text-slate-500 uppercase tracking-wide">Entidades</span>
      </div>
      {#each groupedResults().entidades as item, index}
        {@const globalIdx = getGlobalIndex('entidad', index)}
        <button
          type="button"
          class="w-full text-left px-3 py-2 text-sm hover:bg-gray-100 {globalIdx === selectedIndex ? 'bg-blue-50' : ''}"
          onclick={() => handleSelect(item)}
        >
          <div class="flex items-center gap-2">
            <span>{item.nombre}</span>
            {#if item.sigla}
              <span class="text-slate-400">({item.sigla})</span>
            {/if}
          </div>
          <div class="text-xs text-gray-500">{item.contexto}</div>
        </button>
      {/each}
    {/if}

    {#if groupedResults().objetos.length > 0}
      <div class="px-3 py-1.5 bg-slate-50 border-b {groupedResults().entidades.length > 0 ? 'border-t' : ''}">
        <span class="text-xs font-medium text-slate-500 uppercase tracking-wide">Objetos del Gasto</span>
      </div>
      {#each groupedResults().objetos as item, index}
        {@const globalIdx = getGlobalIndex('objeto_gasto', index)}
        <button
          type="button"
          class="w-full text-left px-3 py-2 text-sm hover:bg-gray-100 {globalIdx === selectedIndex ? 'bg-blue-50' : ''}"
          onclick={() => handleSelect(item)}
        >
          <div class="flex items-center gap-2">
            <span class="font-mono text-xs text-slate-400">{item.codigo}</span>
            <span>{item.nombre}</span>
          </div>
          <div class="text-xs text-gray-500">{item.contexto}</div>
        </button>
      {/each}
    {/if}

    {#if groupedResults().rubros.length > 0}
      <div class="px-3 py-1.5 bg-slate-50 border-b {groupedResults().entidades.length > 0 || groupedResults().objetos.length > 0 ? 'border-t' : ''}">
        <span class="text-xs font-medium text-slate-500 uppercase tracking-wide">Rubros</span>
      </div>
      {#each groupedResults().rubros as item, index}
        {@const globalIdx = getGlobalIndex('rubro', index)}
        <button
          type="button"
          class="w-full text-left px-3 py-2 text-sm hover:bg-gray-100 {globalIdx === selectedIndex ? 'bg-blue-50' : ''}"
          onclick={() => handleSelect(item)}
        >
          <div class="flex items-center gap-2">
            <span class="font-mono text-xs text-slate-400">{item.codigo}</span>
            <span>{item.nombre}</span>
          </div>
          <div class="text-xs text-gray-500">{item.contexto}</div>
        </button>
      {/each}
    {/if}
  </div>
{:else if query.length >= 2}
  <div class="absolute top-full left-0 right-0 mt-1 bg-white border rounded p-3 text-sm text-gray-500">
    Sin resultados para "{query}"
  </div>
{/if}