import { useCallback, useMemo, useState } from 'react'; import { toast } from 'react-toastify'; import AccessTimeIcon from '@mui/icons-material/AccessTime'; import CancelIcon from '@mui/icons-material/Cancel'; import WarningIcon from '@mui/icons-material/Warning'; import { Box, Button, Checkbox, Dialog, DialogActions, DialogContent, DialogTitle, MenuItem, TextField, Typography } from '@mui/material'; import * as NTPApi from 'api/ntp'; import { readNTPSettings } from 'api/ntp'; import { dialogStyle } from 'CustomTheme'; import { useRequest } from 'alova/client'; import { updateState } from 'alova/client'; import type { ValidateFieldsError } from 'async-validator'; import { BlockFormControlLabel, BlockNavigation, ButtonRow, FormLoader, SectionContent, ValidatedTextField, useLayoutTitle } from 'components'; import { useI18nContext } from 'i18n/i18n-react'; import type { NTPSettingsType, Time } from 'types'; import { formatLocalDateTime, updateValueDirty, useRest } from 'utils'; import { validate } from 'validators'; import { NTP_SETTINGS_VALIDATOR } from 'validators/ntp'; import { TIME_ZONES, selectedTimeZone, useTimeZoneSelectItems } from './TZ'; const NTPSettings = () => { const { loadData, saving, data, updateDataValue, origData, dirtyFlags, setDirtyFlags, blocker, saveData, errorMessage } = useRest({ read: NTPApi.readNTPSettings, update: NTPApi.updateNTPSettings }); const { LL } = useI18nContext(); useLayoutTitle('NTP'); // Memoized timezone select items for better performance const timeZoneItems = useTimeZoneSelectItems(); // Memoized selected timezone value const selectedTzValue = useMemo( () => (data ? selectedTimeZone(data.tz_label, data.tz_format) : undefined), [data?.tz_label, data?.tz_format] ); const [localTime, setLocalTime] = useState(''); const [settingTime, setSettingTime] = useState(false); const [processing, setProcessing] = useState(false); const [fieldErrors, setFieldErrors] = useState(); const { send: updateTime } = useRequest( (local_time: Time) => NTPApi.updateTime(local_time), { immediate: false } ); // Memoize updateFormValue to prevent recreation on every render const updateFormValue = useMemo( () => updateValueDirty( origData as unknown as Record, dirtyFlags, setDirtyFlags, updateDataValue as (value: unknown) => void ), [origData, dirtyFlags, setDirtyFlags, updateDataValue] ); // Memoize updateLocalTime handler const updateLocalTime = useCallback( (event: React.ChangeEvent) => setLocalTime(event.target.value), [] ); // Memoize openSetTime handler const openSetTime = useCallback(() => { setLocalTime(formatLocalDateTime(new Date())); setSettingTime(true); }, []); // Memoize configureTime handler const configureTime = useCallback(async () => { setProcessing(true); try { await updateTime({ local_time: formatLocalDateTime(new Date(localTime)) }); toast.success(LL.TIME_SET()); setSettingTime(false); await loadData(); } catch { toast.error(LL.PROBLEM_UPDATING()); } finally { setProcessing(false); } }, [localTime, updateTime, LL, loadData]); // Memoize close dialog handler const handleCloseSetTime = useCallback(() => setSettingTime(false), []); // Memoize validate and submit handler const validateAndSubmit = useCallback(async () => { if (!data) return; try { setFieldErrors(undefined); await validate(NTP_SETTINGS_VALIDATOR, data); await saveData(); } catch (error) { setFieldErrors(error as ValidateFieldsError); } }, [data, saveData]); // Memoize timezone change handler const changeTimeZone = useCallback( (event: React.ChangeEvent) => { void updateState(readNTPSettings(), (settings: NTPSettingsType) => ({ ...settings, tz_label: event.target.value, tz_format: TIME_ZONES[event.target.value] })); updateFormValue(event); }, [updateFormValue] ); // Memoize render content to prevent unnecessary re-renders const renderContent = useMemo(() => { if (!data) { return ; } return ( <> } label={LL.ENABLE_NTP()} /> {LL.TIME_ZONE()}... {timeZoneItems} {!data.enabled && !dirtyFlags.length && ( )} {dirtyFlags && dirtyFlags.length !== 0 && ( )} ); }, [ data, errorMessage, loadData, updateFormValue, fieldErrors, selectedTzValue, changeTimeZone, timeZoneItems, dirtyFlags, openSetTime, saving, validateAndSubmit, LL ]); return ( {blocker ? : null} {renderContent} {LL.SET_TIME(1)} {LL.SET_TIME_TEXT()} ); }; export default NTPSettings;