/* * Copyright (C) 2025 Red Hat, Inc. * SPDX-License-Identifier: LGPL-2.1-or-later */ import cockpit from "cockpit"; import { DateTime } from "luxon"; import React, { useCallback, useContext, useEffect, useState } from "react"; import { Checkbox } from "@patternfly/react-core/dist/esm/components/Checkbox/index.js"; import { DatePicker } from "@patternfly/react-core/dist/esm/components/DatePicker/index.js"; import { Form, FormGroup } from "@patternfly/react-core/dist/esm/components/Form/index.js"; import { Popover } from "@patternfly/react-core/dist/esm/components/Popover/index.js"; import { Switch } from "@patternfly/react-core/dist/esm/components/Switch/index.js"; import { TimePicker } from "@patternfly/react-core/dist/esm/components/TimePicker/index.js"; import { Title } from "@patternfly/react-core/dist/esm/components/Title/index.js"; import { Flex, FlexItem } from "@patternfly/react-core/dist/esm/layouts/Flex/index.js"; import { Stack, StackItem } from "@patternfly/react-core/dist/esm/layouts/Stack/index.js"; import { getNTPEnabled, getSystemDateTime, setNTPEnabled, setSystemDateTime, } from "../../apis/timezone.js"; import { convertToCockpitLang } from "../../helpers/language.js"; import { formatDateInput, getLocalTimeForPicker, getUserLocale, is24HourLocale, isValidDate, } from "../../helpers/timezone.js"; import { LanguageContext, NetworkContext, PageContext } from "../../contexts/Common.jsx"; import { CustomNTP } from "./CustomNTPModal.jsx"; import { TimezoneSection } from "./Timezone.jsx"; import "./DateAndTime.scss"; const _ = cockpit.gettext; const SCREEN_ID = "anaconda-screen-date-time"; const DateAndTimeSection = ({ locale, setSectionValid, timezone }) => { const [autoDateTime, setAutoDateTime] = useState(true); const [isDateTimeValid, setIsDateTimeValid] = useState(true); const [datetime, setDatetime] = useState(DateTime.utc()); const isConnected = useContext(NetworkContext).connected; const [timeFormat, setTimeFormat] = useState(() => is24HourLocale(locale) ? "24" : "ampm" ); // Initial data fetch useEffect(() => { const updateTimeDateData = async () => { const ntpEnabled = await getNTPEnabled(); setAutoDateTime(!!ntpEnabled); const dtIso = await getSystemDateTime(); if (dtIso) { setDatetime( DateTime.fromISO(dtIso, { zone: "utc" }).setZone(timezone) ); } }; updateTimeDateData(); }, [timezone]); const handleAutoDateTime = useCallback(() => { const newValue = !autoDateTime; setAutoDateTime(newValue); setNTPEnabled({ enabled: newValue }); }, [autoDateTime]); // Section validity update useEffect(() => { setSectionValid(autoDateTime || isDateTimeValid); }, [autoDateTime, isDateTimeValid, setSectionValid]); const handleDateChange = (_event, _, newDate) => { const isValid = !!newDate && isValidDate(newDate); setIsDateTimeValid(isValid); if (!isValid) return; const localDate = DateTime.fromJSDate(newDate); const datePart = localDate.setZone(timezone, { keepLocalTime: true }); const combined = datetime.set({ day: datePart.day, month: datePart.month, year: datePart.year, }); setDatetime(combined); if (!autoDateTime && combined.isValid) { setSystemDateTime({ dateTimeSpec: combined.toISO() }); } }; // TimePicker change handler const handleTimeChange = (event, _, hour, minute, seconds, isValid) => { const timeIsEmpty = hour === null || minute === null; const valid = isValid && !timeIsEmpty; setIsDateTimeValid(valid); if (!valid) return; if (typeof hour !== "number" || typeof minute !== "number") return; const updated = datetime.set({ hour, minute, second: seconds || 0, }); setDatetime(updated); if (!autoDateTime && updated.isValid) { setSystemDateTime({ dateTimeSpec: updated.toISO() }); } }; // Always derive these on render const datePickerValue = formatDateInput(datetime); const timePickerValue = getLocalTimeForPicker(datetime, timeFormat === "24"); const autoDateTimeCheckbox = ( ); const autoDateTimeItem = isConnected ? autoDateTimeCheckbox : ( {autoDateTimeCheckbox} ); return ( <> {_("Date and time")} {autoDateTimeItem} setTimeFormat(timeFormat === "24" ? "ampm" : "24")} label={_("Show AM/PM")} /> ); }; export const DateAndTimePage = ({ dispatch }) => { const { setIsFormValid } = useContext(PageContext) ?? {}; const [dateTimeValid, setDateTimeValid] = useState(false); const [timezoneLabel, setTimezoneLabel] = useState(""); const [timezoneValid, setTimezoneValid] = useState(false); const { language } = useContext(LanguageContext); const locale = convertToCockpitLang({ lang: language || getUserLocale() }); useEffect(() => { dispatch({ type: "SET_TIMEZONE_USER_CONFIGURED" }); }, [dispatch]); useEffect(() => { setIsFormValid(dateTimeValid && timezoneValid); }, [dateTimeValid, timezoneValid, setIsFormValid]); return (
); };