/* Copyright (C) 2023-2026 QuantumNous This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . For commercial licensing, please contact support@quantumnous.com */ import { useQuery } from '@tanstack/react-query' import { getSystemOptions } from '../api' export function useSystemOptions() { return useQuery({ queryKey: ['system-options'], queryFn: getSystemOptions, staleTime: 5 * 60 * 1000, }) } type ParseResult = | { success: true; value: T } | { success: false; error: string; fallback: T } function parseOptionValueSafe( value: string, defaultValue: T ): ParseResult { if (typeof defaultValue === 'boolean') { return { success: true, value: (value === 'true' || value === '1') as T, } } if (typeof defaultValue === 'number') { const trimmed = value.trim() if (trimmed === '') { return { success: false, error: 'Empty string for number field', fallback: defaultValue, } } const parsed = Number(trimmed) if (Number.isNaN(parsed)) { return { success: false, error: `Invalid number: "${value}"`, fallback: defaultValue, } } return { success: true, value: parsed as T } } if (Array.isArray(defaultValue)) { try { const parsed = JSON.parse(value) if (!Array.isArray(parsed)) { return { success: false, error: 'Expected array but got non-array JSON', fallback: defaultValue, } } if (defaultValue.length > 0) { const expectedType = typeof defaultValue[0] const invalidElement = parsed.find((el) => typeof el !== expectedType) if (invalidElement !== undefined) { return { success: false, error: `Array element type mismatch: expected ${expectedType}, got ${typeof invalidElement}`, fallback: defaultValue, } } } return { success: true, value: parsed as T } } catch (e) { return { success: false, error: `JSON parse failed: ${e instanceof Error ? e.message : String(e)}`, fallback: defaultValue, } } } return { success: true, value: value as T } } export function getOptionValue< T extends Record, >(options: Array<{ key: string; value: string }> | undefined, defaults: T): T { if (!options) return defaults const result = { ...defaults } const errors: Array<{ key: string; error: string }> = [] options.forEach((option) => { if (option.key in defaults) { const parseResult = parseOptionValueSafe( option.value, defaults[option.key as keyof T] ) if (parseResult.success) { result[option.key as keyof T] = parseResult.value as T[keyof T] } else { result[option.key as keyof T] = parseResult.fallback as T[keyof T] errors.push({ key: option.key, error: parseResult.error }) } } }) if (errors.length > 0 && import.meta.env.DEV) { // eslint-disable-next-line no-console console.warn('[System Options] Parsing errors detected:', errors) } return result }