diff --git a/FRONT/DEV/src/components/settings/SettingItem.tsx b/FRONT/DEV/src/components/settings/SettingItem.tsx index 445f29d..1732b5c 100644 --- a/FRONT/DEV/src/components/settings/SettingItem.tsx +++ b/FRONT/DEV/src/components/settings/SettingItem.tsx @@ -66,19 +66,23 @@ const LabelCheckbox = styled.label` } ` +interface SettingItemProps { + setting: Setting; + value: any; + onChange: (value: any) => void; +} -export const SettingItem = ({ setting }: { setting: Setting }) => { - const { updateSetting } = useSettingsStore(); +export const SettingItem = ({ setting, value, onChange }: SettingItemProps) => { const theme = useTheme(); + const { updateSetting } = useSettingsStore(); - const handleChange = ( - e: ChangeEvent - ) => { - const value = - setting.type === 'boolean' - ? (e.target as HTMLInputElement).checked + const handleChange = (e: ChangeEvent) => { + const newValue = setting.type === 'boolean' + ? (e.target as HTMLInputElement).checked + : setting.type === 'number' + ? Number(e.target.value) : e.target.value; - updateSetting(setting.id, value); + onChange(newValue); }; return ( @@ -122,7 +126,7 @@ export const SettingItem = ({ setting }: { setting: Setting }) => { )} diff --git a/FRONT/DEV/src/components/settings/Settings.tsx b/FRONT/DEV/src/components/settings/Settings.tsx index 097c509..33ca81e 100644 --- a/FRONT/DEV/src/components/settings/Settings.tsx +++ b/FRONT/DEV/src/components/settings/Settings.tsx @@ -53,32 +53,45 @@ const CloseBtn = styled.span` ` export const Settings = ({onClose}: Props) => { - const {settings, activeSection, setActiveSection, initializeSettings} = useSettingsStore(); + const { + settingsConfig, + settingsValues, + activeSection, + setActiveSection, + initializeSettings, + updateSetting + } = useSettingsStore(); + + const settingsBySection = useMemo(() => { + return settingsConfig.reduce((acc, setting) => { + if (!acc[setting.sectionId]) { + acc[setting.sectionId] = []; + } + acc[setting.sectionId].push({ + ...setting, + value: settingsValues[setting.id] ?? setting.defaultValue + }); + return acc; + }, {} as Record); + }, [settingsConfig, settingsValues]); + + const sections = Object.keys(settingsBySection); useEffect(() => { initializeSettings(); }, [initializeSettings]); - const settingsBySection = useMemo(() => { - return settings.reduce((acc, setting) => { - if (!acc[setting.sectionId]) { - acc[setting.sectionId] = []; - } - acc[setting.sectionId].push(setting); - return acc; - }, {} as Record); - }, [settings]); - - - const sections = Object.keys(settingsBySection); - - useEffect(() => { if (sections.length > 0 && !activeSection) { setActiveSection(sections[0]); } }, [sections, activeSection, setActiveSection]); + const handleSave = () => { + onClose(); + }; + + return ( @@ -104,8 +117,13 @@ export const Settings = ({onClose}: Props) => { {activeSection && settingsBySection[activeSection] && ( <> - {settingsBySection[activeSection].map((setting)=>( - + {settingsBySection[activeSection].map((setting) => ( + updateSetting(setting.id, value)} + /> ))} )} @@ -117,7 +135,7 @@ export const Settings = ({onClose}: Props) => { type="button" size="small" title='Сохранить' - onClick={onClose} + onClick={handleSave} /> diff --git a/FRONT/DEV/src/components/workSpace/modules/appModules/usersScanner/modules/TableScanner.tsx b/FRONT/DEV/src/components/workSpace/modules/appModules/usersScanner/modules/TableScanner.tsx index 0689756..6e98453 100644 --- a/FRONT/DEV/src/components/workSpace/modules/appModules/usersScanner/modules/TableScanner.tsx +++ b/FRONT/DEV/src/components/workSpace/modules/appModules/usersScanner/modules/TableScanner.tsx @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, {useEffect, useState} from 'react'; import { DeviceUser } from '../../../../../../store/useDeviceStore'; interface TableScannerProps { @@ -10,6 +10,7 @@ import {buttonNames} from "../../../../../../const/buttons/names"; import {ModalMap} from "../../../../../modalwindows/windowsType"; import {useModalContext} from "../../../../../../store"; import Pagination from "../../../../../UI/Pagination"; +import {useSettingsStore} from "../../../../../../store/settingsStore"; const TableContainer = styled.div` width: 100%; @@ -74,9 +75,19 @@ const TableScanner = ({devices}:TableScannerProps) => { }); }; + const paginateSetting = useSettingsStore(state => + state.settingsValues['paginate-nodes'] ?? + state.settingsConfig.find(s => s.id === 'paginate-nodes')?.defaultValue ?? + 15 + ); + // Пагинация const [currentPage, setCurrentPage] = useState(1); - const [devicesPerPage] = useState(15); + const [devicesPerPage, setDevicesPerPage] = useState(paginateSetting); + + useEffect(() => { + setDevicesPerPage(paginateSetting); + }, [paginateSetting]); const indexOfLastDevice = currentPage * devicesPerPage; const indexOfFirstDevice = indexOfLastDevice - devicesPerPage; diff --git a/FRONT/DEV/src/store/settingsStore.ts b/FRONT/DEV/src/store/settingsStore.ts index 86e72d5..22b451f 100644 --- a/FRONT/DEV/src/store/settingsStore.ts +++ b/FRONT/DEV/src/store/settingsStore.ts @@ -1,10 +1,15 @@ import { create } from 'zustand'; +import { persist } from 'zustand/middleware'; + +type SettingValue = any; +type SettingsDictionary = Record; export type Setting = { id: string; type: 'boolean' | 'select' | 'text' | 'number' | 'button'; label: string; - value: any; + defaultValue: any; + value?: string; min?: number; max?: number; options?: { value: any; label: string }[]; @@ -12,42 +17,31 @@ export type Setting = { }; type SettingsState = { - settings: Setting[]; + settingsConfig: Setting[]; + settingsValues: SettingsDictionary; activeSection: string | null; setActiveSection: (sectionId: string | null) => void; updateSetting: (id: string, value: any) => void; initializeSettings: () => void; + getSetting: (id: string) => Setting & { currentValue: any }; + resetSettings: () => void; }; -export const useSettingsStore = create((set) => ({ - settings: [], - activeSection: null, - - setActiveSection: (sectionId) => set({ activeSection: sectionId }), - - updateSetting: (id, value) => - set((state) => ({ - settings: state.settings.map((setting) => - setting.id === id ? { ...setting, value } : setting - ), - })), - - initializeSettings: () => { - const defaultSettings: Setting[] = [ +const defaultSettings: Setting[] = [ // Узлы подсети { id: 'rescan-nodes', sectionId: 'Узлы подсети', label: 'Интервальное сканирование', type: 'boolean', - value: false, + defaultValue: false, }, { id: 'interval-nodes', sectionId: 'Узлы подсети', label: 'Интервал сканирования узлов (мин)', type: 'number', - value: 60, + defaultValue: 60, min: 1, max: 2880 }, @@ -56,7 +50,7 @@ export const useSettingsStore = create((set) => ({ sectionId: 'Узлы подсети', label: 'Отображаемые имена при отсутствии', type: 'select', - value: 'ip', + defaultValue: 'ip', options: [ { value: 'ip', label: 'IP адрес' }, { value: 'unknown', label: 'Неизвестно' }, @@ -65,9 +59,9 @@ export const useSettingsStore = create((set) => ({ { id: 'paginate-nodes', type: 'number', - label: 'Количество строк на таблице', + label: 'Количество строк в таблице', sectionId: 'Узлы подсети', - value: 20, + defaultValue: 20, min: 1, }, { @@ -75,21 +69,21 @@ export const useSettingsStore = create((set) => ({ type: 'button', label: 'Отображение узлов', sectionId: 'Узлы подсети', - value: 'Настроить', + defaultValue: 'Настроить', }, { id: 'clean-nodes', type: 'button', label: 'Очистить данные сессии', sectionId: 'Узлы подсети', - value: 'Очистить', + defaultValue: 'Очистить', }, { id: 'export-nodes', type: 'button', label: 'Экспорт данных узлов', sectionId: 'Узлы подсети', - value: 'Экспортировать', + defaultValue: 'Экспортировать', }, // Точки доступа @@ -98,14 +92,14 @@ export const useSettingsStore = create((set) => ({ type: 'button', label: 'Очистить данные сессии', sectionId: 'Точки доступа', - value: 'Очистить', + defaultValue: 'Очистить', }, { id: 'export-network', type: 'button', label: 'Экспорт данных точек доступа', sectionId: 'Точки доступа', - value: 'Экспортировать', + defaultValue: 'Экспортировать', }, // Внешний вид @@ -114,7 +108,7 @@ export const useSettingsStore = create((set) => ({ sectionId: 'Внешний вид', label: 'Цветовая тема', type: 'select', - value: 'light', + defaultValue: 'light', options: [ { value: 'light', label: 'Светлая' }, { value: 'dark', label: 'Тёмная' }, @@ -126,13 +120,60 @@ export const useSettingsStore = create((set) => ({ sectionId: 'Внешний вид', label: 'Язык интерфейса', type: 'select', - value: 'ru', + defaultValue: 'ru', options: [ { value: 'ru', label: 'Русский' }, { value: 'en', label: 'Английский' }, ], }, - ]; - set({ settings: defaultSettings }); - }, -})); \ No newline at end of file +]; + +export const useSettingsStore = create()( + persist( + (set, get) => ({ + settingsConfig: defaultSettings, + settingsValues: {}, + activeSection: null, + + setActiveSection: (sectionId) => set({ activeSection: sectionId }), + + updateSetting: (id, value) => + set((state) => ({ + settingsValues: { ...state.settingsValues, [id]: value } + })), + + initializeSettings: () => { + const { settingsValues, settingsConfig } = get(); + const newValues = { ...settingsValues }; + + settingsConfig.forEach(setting => { + if (newValues[setting.id] === undefined) { + newValues[setting.id] = setting.defaultValue; + } + }); + + set({ settingsValues: newValues }); + }, + + getSetting: (id) => { + const setting = get().settingsConfig.find(s => s.id === id); + if (!setting) throw new Error(`Setting ${id} not found`); + return { + ...setting, + currentValue: get().settingsValues[id] ?? setting.defaultValue + }; + }, + + resetSettings: () => set({ settingsValues: {} }), + }), + { + name: 'app-settings', + partialize: (state) => ({ + settingsValues: state.settingsValues + }), + onRehydrateStorage: () => (state) => { + state?.initializeSettings(); + } + } + ) +);