/* Zustand der Ticketliste in der Adresse: status (Reiter-Id), art (Id aus TYPE_FILTERS), dringend (1), q, limit - in dieser Reihenfolge, Standardwerte werden nicht geschrieben. Aus dem Zustand entstehen die Filter fuer Liste und Zaehler (beide muessen dieselben nutzen). */ import { STATUS_GROUPS, DEFAULT_STATUS_GROUPS, statusValuesFor, TYPE_FILTERS } from './ticketStatus' import { ticketPath } from './ticketRoutes' // Reiter: "Aktiv" (alles Laufende), je eine Statusgruppe, zuletzt "Alle" (groups: null = kein Statusfilter) export const LIST_TABS = [ { id: 'aktiv', label: 'Aktiv', groups: DEFAULT_STATUS_GROUPS }, ...STATUS_GROUPS.map((group) => ({ id: group.id, label: group.label, groups: [group.id] })), { id: 'alle', label: 'Alle', groups: null }, ] export const LIST_DEFAULTS = { tab: 'aktiv', typeId: 'orders', urgentOnly: false, search: '', limit: 10 } const MIN_LIMIT = 10 const MAX_LIMIT = 500 const LIMIT_STEP = 10 // Hoch (3) und Kritisch (4) gelten als dringend (siehe ticketStatus.js) const URGENT_PRIORITIES = [3, 4] export function clampLimit(value) { const n = Math.floor(Number(value)) if (!Number.isFinite(n)) return MIN_LIMIT return Math.min(MAX_LIMIT, Math.max(MIN_LIMIT, n)) } // input: URLSearchParams oder String ("?status=done" und "status=done" gehen beide) export function parseListParams(input) { const params = new URLSearchParams(input) const tab = params.get('status') const typeId = params.get('art') const limit = params.get('limit') return { tab: LIST_TABS.some((t) => t.id === tab) ? tab : LIST_DEFAULTS.tab, typeId: TYPE_FILTERS.some((f) => f.id === typeId) ? typeId : LIST_DEFAULTS.typeId, urgentOnly: params.get('dringend') === '1', search: (params.get('q') || '').trim(), limit: limit !== null && /^\d+$/.test(limit) ? clampLimit(limit) : LIST_DEFAULTS.limit, } } export function serializeListParams(state) { const params = new URLSearchParams() if (state.tab !== LIST_DEFAULTS.tab) params.set('status', state.tab) if (state.typeId !== LIST_DEFAULTS.typeId) params.set('art', state.typeId) if (state.urgentOnly) params.set('dringend', '1') if (state.search) params.set('q', state.search) const limit = clampLimit(state.limit) if (limit !== LIST_DEFAULTS.limit) params.set('limit', String(limit)) return params } // Jede Filteraenderung beginnt wieder bei der ersten Seite export function withFilter(state, patch) { return { ...state, ...patch, limit: LIST_DEFAULTS.limit } } // "Mehr laden" export function nextLimit(state) { return clampLimit(Number(state.limit) + LIMIT_STEP) } // Filter fuer den Zaehler eines Reiters: wie die Liste, aber ohne Suche und limit export function countFilters(state, tabId) { const tab = LIST_TABS.find((t) => t.id === tabId) || LIST_TABS[0] const type = TYPE_FILTERS.find((f) => f.id === state.typeId) || TYPE_FILTERS[0] return { status: tab.groups === null ? [] : statusValuesFor(tab.groups), type: [...(type.types || [])], excludeType: type.excludeType, priority: state.urgentOnly ? [...URGENT_PRIORITIES] : [], } } export function listFilters(state) { return { ...countFilters(state, state.tab), search: state.search || undefined, limit: state.limit } } // Altlinks aus den Leads (Liste mit Suchteil woid=100131) fuehren zur Ticketseite und haben Vorrang vor allen Filtern export function woidRedirectTarget(input) { const woid = (new URLSearchParams(input).get('woid') || '').trim() return woid ? ticketPath(woid) : null }