diff --git a/src/components/InputTypes/TimeZone.tsx b/src/components/InputTypes/TimeZone.tsx index 7b659616..ce205c77 100644 --- a/src/components/InputTypes/TimeZone.tsx +++ b/src/components/InputTypes/TimeZone.tsx @@ -1,7 +1,7 @@ /** @jsx jsx */ /** @jsxFrag React.Fragment */ import { jsx, css } from "@emotion/react"; -import React from "react"; +import React, { MutableRefObject, useEffect, useRef } from "react"; import { hiddenInput, invalidStyles } from "../../commonStyles"; import RenderedQuestion from "../Question"; @@ -216,110 +216,127 @@ const getTZ = () => { return recognisedZone ? guessedTimeZoneOffset : false; }; -class TimeZone extends React.Component { - selected_option: React.RefObject | null = null; +const TimeZone: React.FC = ({ question, valid, onBlurHandler }) => { + const containerRef = useRef(null); + const selectedOptionRef = useRef(null); - handler(selected_option: React.RefObject, event: React.ChangeEvent): void { - const option_container = event.target.parentElement; - if (!option_container || !option_container.parentElement || !selected_option.current) { + const handler = (selectedOption: MutableRefObject, event: React.ChangeEvent) => { + const optionContainer = event.target.parentElement; + if (!optionContainer || !optionContainer.parentElement || !selectedOption.current) { return; } - if (!this.props.question?.current) { + if (!question?.current) { throw new Error("Missing ref for select question."); } // Update stored value - this.props.question.current.setState({ value: option_container.textContent }); + question.current.setState({ value: optionContainer.textContent }); // Close the menu - selected_option.current.focus(); - selected_option.current.blur(); - selected_option.current.textContent = option_container.textContent; - } + selectedOption.current.focus(); + selectedOption.current.blur(); + selectedOption.current.textContent = optionContainer.textContent; + }; + + const handleClick = (container: MutableRefObject, selectedOption: MutableRefObject, event: React.MouseEvent | React.KeyboardEvent) => { + if (!container.current || !selectedOption.current) { + return; + } - handle_click( - container: React.RefObject, - selected_option: React.RefObject, - event: React.MouseEvent | React.KeyboardEvent - ): void { - if (!container.current || !selected_option.current || (event.type === "keydown" && (event as React.KeyboardEvent).code !== "Space")) { + // if it is a keyboard event and it is not the space key, return + if (event.type === "keydown" && (event as React.KeyboardEvent).code !== "Space") { return; } // Check if menu is open if (container.current.contains(document.activeElement)) { // Close menu - selected_option.current.focus(); - selected_option.current.blur(); + selectedOption.current.focus(); + selectedOption.current.blur(); event.preventDefault(); } - } + }; - focusOption(): void { - if (!this.props.question?.current) { + const focusOption = () => { + if (!question?.current) { throw new Error("Missing ref for select question."); } - if (!this.props.question.current.realState.value) { - this.props.question.current.setState({ value: "temporary" }); - this.props.onBlurHandler(); - this.props.question.current.setState({ value: null }); + if (!question.current.realState.value) { + question.current.setState({ value: "temporary" }); + onBlurHandler(); + question.current.setState({ value: null }); } - } + }; - componentDidMount() { + useEffect(() => { const tz = getTZ(); if (tz) { - if (!this.props.question.current) { + if (!question.current) { console.warn("No ref to question component in TimeZone."); + + setTimeout(() => { + console.log(question); + }, 5000); } else { - this.props.question.current.setState({ value: tz }); + question.current.setState({ value: tz }); } } - } - - render(): JSX.Element { - const container_ref: React.RefObject = React.createRef(); - const selected_option_ref: React.RefObject = React.createRef(); - - this.selected_option = selected_option_ref; - - const handle_click = (event: React.MouseEvent | React.KeyboardEvent) => this.handle_click(container_ref, selected_option_ref, event); - - const tz = getTZ(); - - const FOUND_COPY = "We have tried to guess your timezone based on your system settings. If this is incorrect, please select the correct timezone from the list below."; - const NOT_FOUND_COPY = "We could not automatically detect your timezone. Please select it from the list below."; - - return ( - <> -
-

{tz ? FOUND_COPY : NOT_FOUND_COPY}

- -

Timezones are displayed as offsets from UTC. For example, UTC+1 is one hour ahead of UTC, and UTC-5 is five hours behind UTC.

-
-
-
- -
{tz ? tz : "..."}
+ }, [question]); + + const tz = getTZ(); + + const FOUND_COPY = "We have tried to guess your timezone based on your system settings. If this is incorrect, please select the correct timezone from the list below."; + const NOT_FOUND_COPY = "We could not automatically detect your timezone. Please select it from the list below."; + + return ( + <> +
+

{tz ? FOUND_COPY : NOT_FOUND_COPY}

+ +

Timezones are displayed as offsets from UTC. For example, UTC+1 is one hour ahead of UTC, and UTC-5 is five hours behind UTC.

+
+
+
+ +
handleClick(containerRef, selectedOptionRef, event)} + onKeyDown={(event) => handleClick(containerRef, selectedOptionRef, event)} + > + {tz ? tz : "..."}
+
-
-
- {TIMEZONE_OFFSETS.map((option, index) => ( -
- this.handler.call(this, selected_option_ref, event)} /> -
{option}
-
- ))} -
+
+
+ {TIMEZONE_OFFSETS.map((option, index) => ( +
+ handler(selectedOptionRef, event)} + /> +
{option}
+
+ ))}
- - ); - } -} +
+ + ); +}; export default TimeZone;