From 808ed1d2f1164d9fd1114586c68a1f925bf73ddf Mon Sep 17 00:00:00 2001 From: Paul Nothaft Date: Fri, 16 Jan 2026 08:57:52 +0100 Subject: [PATCH] fix: checkbox and toggle settings not persisting after page refresh PostgreSQL's json column type returns parsed values directly (boolean false instead of string "false"). The backend code used a truthy check which failed for boolean false values, causing null to be returned instead of the actual false value. Changed condition from `if (setting.setting_value)` to explicit null check `if (setting.setting_value !== null && setting.setting_value !== undefined)` and added handling for already-parsed json column values. Fixes #117 --- backend/src/routes/adminSettings.js | 40 +++++++++++++++++++---------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/backend/src/routes/adminSettings.js b/backend/src/routes/adminSettings.js index 64896bbf..f650fc12 100644 --- a/backend/src/routes/adminSettings.js +++ b/backend/src/routes/adminSettings.js @@ -102,13 +102,20 @@ router.get('/', adminAuth, requirePermission('settings.view'), async (req, res) // Convert to object format const settingsObject = {}; settings.forEach(setting => { - if (setting.setting_value) { - try { - // Try to parse as JSON first - settingsObject[setting.setting_key] = JSON.parse(setting.setting_value); - } catch (e) { - // If it's not valid JSON, use the raw value + // Check for null/undefined explicitly to handle boolean false and 0 values + // PostgreSQL json column returns parsed values (false as boolean, not string) + if (setting.setting_value !== null && setting.setting_value !== undefined) { + // If the value is already parsed (from json column), use it directly + if (typeof setting.setting_value !== 'string') { settingsObject[setting.setting_key] = setting.setting_value; + } else { + try { + // Try to parse as JSON first + settingsObject[setting.setting_key] = JSON.parse(setting.setting_value); + } catch (e) { + // If it's not valid JSON, use the raw value + settingsObject[setting.setting_key] = setting.setting_value; + } } } else { settingsObject[setting.setting_key] = null; @@ -129,17 +136,24 @@ router.get('/:type', adminAuth, requirePermission('settings.view'), async (req, const settings = await db('app_settings') .where('setting_type', type) .select('*'); - + // Convert to object format const settingsObject = {}; settings.forEach(setting => { - if (setting.setting_value) { - try { - // Try to parse as JSON first - settingsObject[setting.setting_key] = JSON.parse(setting.setting_value); - } catch (e) { - // If it's not valid JSON, use the raw value + // Check for null/undefined explicitly to handle boolean false and 0 values + // PostgreSQL json column returns parsed values (false as boolean, not string) + if (setting.setting_value !== null && setting.setting_value !== undefined) { + // If the value is already parsed (from json column), use it directly + if (typeof setting.setting_value !== 'string') { settingsObject[setting.setting_key] = setting.setting_value; + } else { + try { + // Try to parse as JSON first + settingsObject[setting.setting_key] = JSON.parse(setting.setting_value); + } catch (e) { + // If it's not valid JSON, use the raw value + settingsObject[setting.setting_key] = setting.setting_value; + } } } else { settingsObject[setting.setting_key] = null;