diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..753bc57 --- /dev/null +++ b/settings.json @@ -0,0 +1,3 @@ +{ + "weekNavigationEnabled": false +} \ No newline at end of file diff --git a/src/pages/admin.tsx b/src/pages/admin.tsx index 072cdf6..4d5d3e6 100644 --- a/src/pages/admin.tsx +++ b/src/pages/admin.tsx @@ -113,7 +113,10 @@ export default function AdminPage({ groups: initialGroups, settings: initialSett } const handleUpdateSettings = async (newSettings: AppSettings) => { - setLoading(true) + // Сохраняем предыдущее состояние для отката при ошибке + const previousSettings = settings + // Оптимистичное обновление UI + setSettings(newSettings) setError(null) try { @@ -126,14 +129,17 @@ export default function AdminPage({ groups: initialGroups, settings: initialSett const data = await res.json() if (res.ok && data.success) { + // Обновляем состояние из ответа сервера (для синхронизации) setSettings(data.settings) } else { + // Откатываем изменения при ошибке + setSettings(previousSettings) setError(data.error || 'Ошибка при обновлении настроек') } } catch (err) { + // Откатываем изменения при ошибке + setSettings(previousSettings) setError('Ошибка соединения с сервером') - } finally { - setLoading(false) } } diff --git a/src/pages/api/admin/check-auth.ts b/src/pages/api/admin/check-auth.ts index 771d5ca..56718a3 100644 --- a/src/pages/api/admin/check-auth.ts +++ b/src/pages/api/admin/check-auth.ts @@ -20,3 +20,4 @@ export default function handler( + diff --git a/src/pages/api/admin/login.ts b/src/pages/api/admin/login.ts index d04c681..58cf1a6 100644 --- a/src/pages/api/admin/login.ts +++ b/src/pages/api/admin/login.ts @@ -32,3 +32,4 @@ export default function handler( + diff --git a/src/pages/api/admin/logout.ts b/src/pages/api/admin/logout.ts index 820cc94..28db898 100644 --- a/src/pages/api/admin/logout.ts +++ b/src/pages/api/admin/logout.ts @@ -20,3 +20,4 @@ export default function handler( + diff --git a/src/pages/api/admin/settings.ts b/src/pages/api/admin/settings.ts index a3d2d9c..8bbdf52 100644 --- a/src/pages/api/admin/settings.ts +++ b/src/pages/api/admin/settings.ts @@ -34,7 +34,11 @@ async function handler( try { saveSettings(settings) - res.status(200).json({ success: true, settings }) + // Сбрасываем кеш и загружаем свежие настройки для подтверждения + const { clearSettingsCache } = await import('@/shared/data/settings-loader') + clearSettingsCache() + const savedSettings = loadSettings() + res.status(200).json({ success: true, settings: savedSettings }) } catch (error) { console.error('Error saving settings:', error) res.status(500).json({ error: 'Failed to save settings' }) diff --git a/src/shared/data/settings-loader.ts b/src/shared/data/settings-loader.ts index 437c225..cd2d8cf 100644 --- a/src/shared/data/settings-loader.ts +++ b/src/shared/data/settings-loader.ts @@ -6,6 +6,8 @@ export type AppSettings = { } let cachedSettings: AppSettings | null = null +let cachedSettingsPath: string | null = null +let cachedSettingsMtime: number | null = null const defaultSettings: AppSettings = { weekNavigationEnabled: true @@ -13,13 +15,9 @@ const defaultSettings: AppSettings = { /** * Загружает настройки из JSON файла - * Использует кеш для оптимизации в production + * Проверяет время модификации файла для инвалидации кеша */ export function loadSettings(): AppSettings { - if (cachedSettings) { - return cachedSettings - } - // В production Next.js может использовать другую структуру директорий // Пробуем несколько путей const possiblePaths = [ @@ -28,24 +26,51 @@ export function loadSettings(): AppSettings { path.join(process.cwd(), 'settings.json'), ] + // Ищем существующий файл + let foundPath: string | null = null for (const filePath of possiblePaths) { + if (fs.existsSync(filePath)) { + foundPath = filePath + break + } + } + + // Если файл найден, проверяем, изменился ли он + if (foundPath) { try { - if (fs.existsSync(filePath)) { - const fileContents = fs.readFileSync(filePath, 'utf8') - const settings = JSON.parse(fileContents) as AppSettings - - // Убеждаемся, что все обязательные поля присутствуют - const mergedSettings: AppSettings = { - ...defaultSettings, - ...settings - } - - cachedSettings = mergedSettings - return mergedSettings + const stats = fs.statSync(foundPath) + const mtime = stats.mtimeMs + + // Если файл изменился или путь изменился, сбрасываем кеш + if (cachedSettings && (cachedSettingsPath !== foundPath || cachedSettingsMtime !== mtime)) { + cachedSettings = null + cachedSettingsPath = null + cachedSettingsMtime = null } + + // Если кеш валиден, возвращаем его + if (cachedSettings && cachedSettingsPath === foundPath && cachedSettingsMtime === mtime) { + return cachedSettings + } + + // Загружаем файл заново + const fileContents = fs.readFileSync(foundPath, 'utf8') + const settings = JSON.parse(fileContents) as AppSettings + + // Убеждаемся, что все обязательные поля присутствуют + const mergedSettings: AppSettings = { + ...defaultSettings, + ...settings + } + + cachedSettings = mergedSettings + cachedSettingsPath = foundPath + cachedSettingsMtime = mtime + + return mergedSettings } catch (error) { - // Пробуем следующий путь - continue + console.error('Error reading settings.json:', error) + // Продолжаем дальше, чтобы создать файл с настройками по умолчанию } } @@ -59,7 +84,12 @@ export function loadSettings(): AppSettings { } fs.writeFileSync(mainPath, JSON.stringify(defaultSettings, null, 2), 'utf8') + + const stats = fs.statSync(mainPath) cachedSettings = defaultSettings + cachedSettingsPath = mainPath + cachedSettingsMtime = stats.mtimeMs + return defaultSettings } catch (error) { console.error('Error creating settings.json:', error) @@ -72,25 +102,66 @@ export function loadSettings(): AppSettings { * Сохраняет настройки в JSON файл */ export function saveSettings(settings: AppSettings): void { - // Всегда сохраняем в основной путь - const filePath = path.join(process.cwd(), 'src/shared/data/settings.json') + // Сначала пытаемся найти существующий файл + const possiblePaths = [ + path.join(process.cwd(), 'src/shared/data/settings.json'), + path.join(process.cwd(), '.next/standalone/src/shared/data/settings.json'), + path.join(process.cwd(), 'settings.json'), + ] + + // Объединяем с настройками по умолчанию для сохранения всех полей + const mergedSettings: AppSettings = { + ...defaultSettings, + ...settings + } + + // Ищем существующий файл + let targetPath: string | null = null + for (const filePath of possiblePaths) { + if (fs.existsSync(filePath)) { + targetPath = filePath + break + } + } + + // Если файл не найден, используем основной путь + if (!targetPath) { + targetPath = path.join(process.cwd(), 'src/shared/data/settings.json') + } try { // Создаем директорию, если её нет - const dir = path.dirname(filePath) + const dir = path.dirname(targetPath) if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }) } - // Объединяем с настройками по умолчанию для сохранения всех полей - const mergedSettings: AppSettings = { - ...defaultSettings, - ...settings + // Сохраняем файл + fs.writeFileSync(targetPath, JSON.stringify(mergedSettings, null, 2), 'utf8') + + // Обновляем кеш с новыми метаданными + try { + const stats = fs.statSync(targetPath) + cachedSettings = mergedSettings + cachedSettingsPath = targetPath + cachedSettingsMtime = stats.mtimeMs + } catch (error) { + // Если не удалось получить stats, просто обновляем кеш + cachedSettings = mergedSettings + cachedSettingsPath = targetPath + cachedSettingsMtime = null } - fs.writeFileSync(filePath, JSON.stringify(mergedSettings, null, 2), 'utf8') - // Сбрасываем кеш - cachedSettings = null + // Также сохраняем в другие возможные пути для совместимости (если они существуют) + for (const filePath of possiblePaths) { + if (filePath !== targetPath && fs.existsSync(path.dirname(filePath))) { + try { + fs.writeFileSync(filePath, JSON.stringify(mergedSettings, null, 2), 'utf8') + } catch (error) { + // Игнорируем ошибки при сохранении в дополнительные пути + } + } + } } catch (error) { console.error('Error saving settings.json:', error) throw new Error('Failed to save settings') @@ -102,6 +173,8 @@ export function saveSettings(settings: AppSettings): void { */ export function clearSettingsCache(): void { cachedSettings = null + cachedSettingsPath = null + cachedSettingsMtime = null } diff --git a/src/shared/data/settings.json b/src/shared/data/settings.json index 82082ee..753bc57 100644 --- a/src/shared/data/settings.json +++ b/src/shared/data/settings.json @@ -1,4 +1,3 @@ { "weekNavigationEnabled": false -} - +} \ No newline at end of file