Composables

useFogliList

Lista fogli con ricerca full-text debounced, filtri tipo (all/mine/shared/templates), paginazione e CRUD veloce.

Signature

function useFogliList(): UseFogliListReturn

Gestisce lista paginata di fogli accessibili all'utente corrente, con search full-text, filtri tipo, paginazione e CRUD veloce (crea/duplica/rinomina/elimina).

Risultato

interface UseFogliListReturn {
  fogli: Ref<FoglioDiCalcolo[]>
  templates: ComputedRef<FoglioDiCalcolo[]>
  totaleFogli: Ref<number>
  isLoading: Ref<boolean>
  error: Ref<string | null>
  filters: Ref<FoglioFilters>
  hasNextPage: ComputedRef<boolean>
  hasPrevPage: ComputedRef<boolean>
  load(): Promise<void>
  setFilter(key: keyof FoglioFilters, value: unknown): void
  resetFilters(): void
  crea(request: CreateFoglioRequest): Promise<number>
  duplica(idfolio: number): Promise<number>
  elimina(idfolio: number): Promise<void>
  rinomina(idfolio: number, nuovoNome: string): Promise<void>
  creaFromTemplate(templateId: number, nome: string): Promise<number>
  refresh(): Promise<void>
}

Filtri (FoglioFilters)

interface FoglioFilters {
  searchText: string                              // ricerca full-text
  tipo: 'all' | 'mine' | 'shared' | 'templates'
  page: number                                    // 0-based
  pageSize: number                                // default 20
}

Stato iniziale:

{ searchText: '', tipo: 'all', page: 0, pageSize: 20 }

Comportamento

Watcher reattivo

watch(filters, debouncedLoad, { deep: true })

Ogni cambio di filtri triggera load() dopo 300ms di pausa (debounce). Se cambia searchText, la pagina viene resettata a 0 prima del fetch.

Load

load() — chiama FogliPostgrestService.listaFogli(filters)
       → fogli.value = result.items
       → totaleFogli.value = result.total

Se la query fallisce, error.value viene popolato col messaggio.

Ricerca full-text

Se searchText è non vuoto, viene usata la vista v_foglidicalcolo_ricerca con tsv_search=plfts(italian).{q}. Altrimenti v_foglidicalcolo_lista.

Filtri tipo

tipoQuery PostgREST aggiunta
'all'(nessuna)
'mine'permesso_effettivo=eq.proprietario
'shared'permesso_effettivo=neq.proprietario
'templates'istemplate=eq.true

Paginazione

hasNextPage = (filters.page + 1) * filters.pageSize < totaleFogli
hasPrevPage = filters.page > 0
fogliList.setFilter('page', fogliList.filters.value.page + 1)
// → debouncedLoad scatta dopo 300ms

Operazioni CRUD

crea(request)

crea(request: CreateFoglioRequest): Promise<number>

POST /foglidicalcolo con request. A successo:

  • await load() per refresh lista
  • ritorna idfolio del nuovo foglio

duplica(idfolio)

RPC POST /rpc/duplica_foglio con p_idfolio. A successo:

  • await load() per refresh lista
  • ritorna idfolio del foglio duplicato

elimina(idfolio)

RPC POST /rpc/elimina_foglio o DELETE /foglidicalcolo?idfolio=eq.{id}. A successo:

  • aggiorna localmente fogli.value rimuovendo la riga
  • decrementa totaleFogli
L'eliminazione non chiede conferma: la conferma deve essere implementata dal componente chiamante (vedi FogliListView che usa confirm.require).

rinomina(idfolio, nuovoNome)

PATCH /foglidicalcolo?idfolio=eq.{id} con { nome: nuovoNome }. A successo:

  • aggiorna localmente la riga in fogli.value

creaFromTemplate(templateId, nome)

Combinazione di duplicaFoglio(templateId) + aggiornaDati(nuovoId, { nome }). A successo:

  • await load() per refresh
  • ritorna idfolio del foglio derivato

Computed templates

templates = computed(() => fogli.value.filter((f) => f.istemplate))

Filtra in-memory i fogli template dalla lista corrente. Non fa una query separata: dipende dal filtro tipo attivo (se tipo='all', mostra tutti i template visibili nella pagina corrente).

Esempio

<script setup lang="ts">
import { useFogliList } from '@pzeta/vue-foglidicalcolo'

const fogliList = useFogliList()
await fogliList.load()

function cercaFatturato() {
  fogliList.setFilter('searchText', 'fatturato')
  // → debounced load dopo 300ms, vista v_foglidicalcolo_ricerca
}

async function nuovo() {
  const id = await fogliList.crea({
    nome: 'Nuovo Foglio',
    descrizione: 'Bozza vuota',
    istemplate: false,
    ispubblico: false,
  })
  console.log('Creato:', id)
}
</script>

<template>
  <input v-model="fogliList.filters.value.searchText" />
  <select v-model="fogliList.filters.value.tipo">
    <option value="all">Tutti</option>
    <option value="mine">Miei</option>
    <option value="shared">Condivisi</option>
    <option value="templates">Template</option>
  </select>

  <ul>
    <li v-for="f in fogliList.fogli.value" :key="f.idfolio">
      {{ f.nome }} — {{ f.permesso_effettivo }}
    </li>
  </ul>

  <button :disabled="!fogliList.hasPrevPage.value"
          @click="fogliList.setFilter('page', fogliList.filters.value.page - 1)">
    ◀ Prev
  </button>
  <button :disabled="!fogliList.hasNextPage.value"
          @click="fogliList.setFilter('page', fogliList.filters.value.page + 1)">
    Next ▶
  </button>

  <button @click="nuovo">+ Nuovo</button>
</template>

Tipi correlati