-
- {autocomplete}
+ // length will only be > 0 if enabled
+ if (filtered.length > 0 && input.length > 0) {
+ autocomplete = (
+
+ {filtered.map((suggestion) => (
+
+ {suggestion}
+
+ ))}
);
}
-}
+
+ return (
+
+
+ {autocomplete}
+
+ );
+};
export { Autocomplete as default, Autocomplete };
diff --git a/src/features/search/options/SearchOptions.jsx b/src/features/search/options/SearchOptions.jsx
index 77b545fb..cb4a878a 100644
--- a/src/features/search/options/SearchOptions.jsx
+++ b/src/features/search/options/SearchOptions.jsx
@@ -1,5 +1,4 @@
import variables from 'config/variables';
-import { PureComponent } from 'react';
import { MdOutlineWarning } from 'react-icons/md';
import { Header, Row, Content, Action, PreferencesWrapper } from 'components/Layout/Settings';
@@ -7,65 +6,62 @@ import { Checkbox } from 'components/Form/Settings';
import EventBus from 'utils/eventbus';
-class SearchOptions extends PureComponent {
-
- render() {
- const SEARCH_SECTION = 'modals.main.settings.sections.search';
-
- const ChromePolicyWarning = () => {
- return (
-
-
-
- Search Engine Selection Removed
- {variables.getMessage(`${SEARCH_SECTION}.chrome_policy_warning`)}
-
-
- );
- };
-
- const AdditionalOptions = () => {
- return (
-
-
-
- {/* not supported on firefox */}
- {navigator.userAgent.includes('Chrome') && typeof InstallTrigger === 'undefined' ? (
-
- ) : null}
-
-
-
- );
- };
+const SearchOptions = () => {
+ const SEARCH_SECTION = 'modals.main.settings.sections.search';
+ const ChromePolicyWarning = () => {
return (
- <>
-
-
-
-
-
- >
+
+
+
+ Search Engine Selection Removed
+ {variables.getMessage(`${SEARCH_SECTION}.chrome_policy_warning`)}
+
+
);
- }
-}
+ };
+
+ const AdditionalOptions = () => {
+ return (
+
+
+
+ {/* not supported on firefox */}
+ {navigator.userAgent.includes('Chrome') && typeof InstallTrigger === 'undefined' ? (
+
+ ) : null}
+
+
+
+ );
+ };
+
+ return (
+ <>
+
+
+
+
+
+ >
+ );
+};
export { SearchOptions as default, SearchOptions };
diff --git a/src/features/time/Clock.jsx b/src/features/time/Clock.jsx
index 36a96334..04694305 100644
--- a/src/features/time/Clock.jsx
+++ b/src/features/time/Clock.jsx
@@ -1,4 +1,4 @@
-import { PureComponent } from 'react';
+import { useState, useEffect, useRef } from 'react';
import { convertTimezone } from 'utils/date';
import { AnalogClock } from './components/AnalogClock';
@@ -6,29 +6,25 @@ import { VerticalClock } from './components/VerticalClock';
import EventBus from 'utils/eventbus';
import './clock.scss';
-export default class Clock extends PureComponent {
- constructor() {
- super();
- this.timer = undefined;
- this.state = {
- timeType: localStorage.getItem('timeType'),
- time: '',
- finalHour: '',
- finalMinute: '',
- finalSeconds: '',
- ampm: '',
- nowGlobal: new Date(),
- };
- }
+const Clock = () => {
+ const [timeType] = useState(localStorage.getItem('timeType'));
+ const [time, setTime] = useState('');
+ const [finalHour, setFinalHour] = useState('');
+ const [finalMinute, setFinalMinute] = useState('');
+ const [finalSeconds, setFinalSeconds] = useState('');
+ const [ampm, setAmpm] = useState('');
+ const [display, setDisplay] = useState('block');
+ const [fontSize, setFontSize] = useState('4em');
+ const timerRef = useRef(undefined);
- startTime(
+ const startTime = (
time = localStorage.getItem('seconds') === 'true' ||
localStorage.getItem('timeType') === 'analogue'
? 1000 - (Date.now() % 1000)
: 60000 - (Date.now() % 60000),
- ) {
- this.timer = setTimeout(() => {
+ ) => {
+ timerRef.current = setTimeout(() => {
let now = new Date();
const timezone = localStorage.getItem('timezone');
if (timezone && timezone !== 'auto') {
@@ -37,16 +33,14 @@ export default class Clock extends PureComponent {
switch (localStorage.getItem('timeType')) {
case 'percentageComplete':
- this.setState({
- time: (now.getHours() / 24).toFixed(2).replace('0.', '') + '%',
- ampm: '',
- });
+ setTime((now.getHours() / 24).toFixed(2).replace('0.', '') + '%');
+ setAmpm('');
break;
case 'analogue':
// load analog clock css
import('react-clock/dist/Clock.css');
- this.setState({ time: now });
+ setTime(now);
break;
default: {
// Default clock
@@ -56,27 +50,24 @@ export default class Clock extends PureComponent {
if (localStorage.getItem('seconds') === 'true') {
sec = `:${('00' + now.getSeconds()).slice(-2)}`;
- this.setState({ finalSeconds: `${('00' + now.getSeconds()).slice(-2)}` });
+ setFinalSeconds(`${('00' + now.getSeconds()).slice(-2)}`);
}
if (localStorage.getItem('timeformat') === 'twentyfourhour') {
if (zero === 'false') {
time = `${now.getHours()}:${('00' + now.getMinutes()).slice(-2)}:${sec}`;
- this.setState({
- finalHour: `${now.getHours()}`,
- finalMinute: `${('00' + now.getMinutes()).slice(-2)}`,
- });
+ setFinalHour(`${now.getHours()}`);
+ setFinalMinute(`${('00' + now.getMinutes()).slice(-2)}`);
} else {
time = `${('00' + now.getHours()).slice(-2)}:${('00' + now.getMinutes()).slice(
-2,
)}${sec}`;
- this.setState({
- finalHour: `${('00' + now.getHours()).slice(-2)}`,
- finalMinute: `${('00' + now.getMinutes()).slice(-2)}`,
- });
+ setFinalHour(`${('00' + now.getHours()).slice(-2)}`);
+ setFinalMinute(`${('00' + now.getMinutes()).slice(-2)}`);
}
- this.setState({ time, ampm: '' });
+ setTime(time);
+ setAmpm('');
} else {
// 12 hour
let hours = now.getHours();
@@ -89,80 +80,76 @@ export default class Clock extends PureComponent {
if (zero === 'false') {
time = `${hours}:${('00' + now.getMinutes()).slice(-2)}${sec}`;
- this.setState({
- finalHour: `${hours}`,
- finalMinute: `${('00' + now.getMinutes()).slice(-2)}`,
- });
+ setFinalHour(`${hours}`);
+ setFinalMinute(`${('00' + now.getMinutes()).slice(-2)}`);
} else {
time = `${('00' + hours).slice(-2)}:${('00' + now.getMinutes()).slice(-2)}${sec}`;
- this.setState({
- finalHour: `${('00' + hours).slice(-2)}`,
- finalMinute: `${('00' + now.getMinutes()).slice(-2)}`,
- });
+ setFinalHour(`${('00' + hours).slice(-2)}`);
+ setFinalMinute(`${('00' + now.getMinutes()).slice(-2)}`);
}
- this.setState({ time, ampm: now.getHours() > 11 ? 'PM' : 'AM' });
+ setTime(time);
+ setAmpm(now.getHours() > 11 ? 'PM' : 'AM');
}
break;
}
}
- this.startTime();
+ startTime();
}, time);
- }
+ };
- componentDidMount() {
- EventBus.on('refresh', (data) => {
+ useEffect(() => {
+ const handleRefresh = (data) => {
if (data === 'clock' || data === 'timezone') {
- const element = document.querySelector('.clock-container');
-
if (localStorage.getItem('time') === 'false') {
- return (element.style.display = 'none');
+ setDisplay('none');
+ return;
}
- this.timer = null;
- this.startTime(0);
+ timerRef.current = null;
+ startTime(0);
- element.style.display = 'block';
- element.style.fontSize = `${
- 4 * Number((localStorage.getItem('zoomClock') || 100) / 100)
- }em`;
+ setDisplay('block');
+ setFontSize(`${4 * Number((localStorage.getItem('zoomClock') || 100) / 100)}em`);
}
- });
+ };
if (localStorage.getItem('timeType') !== 'analogue') {
- document.querySelector('.clock-container').style.fontSize = `${
- 4 * Number((localStorage.getItem('zoomClock') || 100) / 100)
- }em`;
+ setFontSize(`${4 * Number((localStorage.getItem('zoomClock') || 100) / 100)}em`);
}
- this.startTime(0);
+ startTime(0);
+
+ EventBus.on('refresh', handleRefresh);
+ return () => {
+ EventBus.off('refresh');
+ if (timerRef.current) {
+ clearTimeout(timerRef.current);
+ }
+ };
+ }, []);
+
+ if (localStorage.getItem('timeType') === 'analogue') {
+ return
;
}
- componentWillUnmount() {
- EventBus.off('refresh');
- }
-
- render() {
- if (localStorage.getItem('timeType') === 'analogue') {
- return
;
- }
-
- if (localStorage.getItem('timeType') === 'verticalClock') {
- return (
-
- );
- }
-
+ if (localStorage.getItem('timeType') === 'verticalClock') {
return (
-
- {this.state.time}
- {this.state.ampm}
-
+
);
}
-}
+
+ return (
+
+ {time}
+ {ampm}
+
+ );
+};
+
+export { Clock as default, Clock };
diff --git a/src/features/time/Date.jsx b/src/features/time/Date.jsx
index 0cc764b1..b0fe4678 100644
--- a/src/features/time/Date.jsx
+++ b/src/features/time/Date.jsx
@@ -1,26 +1,23 @@
import variables from 'config/variables';
-import { PureComponent, createRef } from 'react';
+import { useState, useEffect, useRef } from 'react';
import { nth, convertTimezone } from 'utils/date';
import EventBus from 'utils/eventbus';
import './date.scss';
-export default class DateWidget extends PureComponent {
- constructor() {
- super();
- this.state = {
- date: '',
- weekNumber: null,
- };
- this.date = createRef();
- }
+const DateWidget = () => {
+ const [date, setDate] = useState('');
+ const [weekNumber, setWeekNumber] = useState(null);
+ const [display, setDisplay] = useState('block');
+ const [fontSize, setFontSize] = useState('1em');
+ const dateRef = useRef();
/**
* Get the week number of the year for the given date.
* @param {Date} date
*/
- getWeekNumber(date) {
+ const getWeekNumber = (date) => {
const dateToday = new Date(date.valueOf());
const dayNumber = (dateToday.getDay() + 6) % 7;
@@ -32,39 +29,37 @@ export default class DateWidget extends PureComponent {
dateToday.setMonth(0, 1 + ((4 - dateToday.getDay() + 7) % 7));
}
- this.setState({
- weekNumber: `${variables.getMessage('widgets.date.week')} ${
+ setWeekNumber(
+ `${variables.getMessage('widgets.date.week')} ${
1 + Math.ceil((firstThursday - dateToday) / 604800000)
}`,
- });
- }
+ );
+ };
- getDate() {
+ const getDate = () => {
let date = new Date();
const timezone = localStorage.getItem('timezone');
if (timezone && timezone !== 'auto') {
date = convertTimezone(date, timezone);
}
-
+
if (localStorage.getItem('weeknumber') === 'true') {
- this.getWeekNumber(date);
- } else if (this.state.weekNumber !== null) {
- this.setState({
- weekNumber: null,
- });
+ getWeekNumber(date);
+ } else if (weekNumber !== null) {
+ setWeekNumber(null);
}
-
+
if (localStorage.getItem('dateType') === 'short') {
const dateDay = date.getDate();
const dateMonth = date.getMonth() + 1;
const dateYear = date.getFullYear();
-
+
const zero = localStorage.getItem('datezero') === 'true';
-
+
let day = zero ? ('00' + dateDay).slice(-2) : dateDay;
let month = zero ? ('00' + dateMonth).slice(-2) : dateMonth;
let year = dateYear;
-
+
switch (localStorage.getItem('dateFormat')) {
case 'MDY':
day = dateMonth;
@@ -78,7 +73,7 @@ export default class DateWidget extends PureComponent {
default:
break;
}
-
+
let format;
switch (localStorage.getItem('shortFormat')) {
case 'dots':
@@ -96,22 +91,22 @@ export default class DateWidget extends PureComponent {
default:
break;
}
-
- this.setState({
- date: format,
- });
+
+ setDate(format);
} else {
// Long date
const lang = variables.languagecode.split('_')[0];
- const datenth = localStorage.getItem('datenth') === 'true' ? nth(date.getDate()) : date.getDate();
- const dateDay = localStorage.getItem('dayofweek') === 'true'
- ? date.toLocaleDateString(lang, { weekday: 'long' })
- : '';
+ const datenth =
+ localStorage.getItem('datenth') === 'true' ? nth(date.getDate()) : date.getDate();
+ const dateDay =
+ localStorage.getItem('dayofweek') === 'true'
+ ? date.toLocaleDateString(lang, { weekday: 'long' })
+ : '';
const dateMonth = date.toLocaleDateString(lang, { month: 'long' });
const dateYear = date.getFullYear();
-
+
let formattedDate;
-
+
switch (localStorage.getItem('longFormat')) {
case 'MDY':
formattedDate = `${dateMonth} ${datenth}, ${dateYear}${dateDay ? `, ${dateDay}` : ''}`;
@@ -124,45 +119,41 @@ export default class DateWidget extends PureComponent {
formattedDate = `${datenth} ${dateMonth} ${dateYear}${dateDay ? `, ${dateDay}` : ''}`;
break;
}
-
- this.setState({
- date: formattedDate,
- });
+
+ setDate(formattedDate);
}
- }
-
- componentDidMount() {
- EventBus.on('refresh', (data) => {
+ };
+
+ useEffect(() => {
+ const handleRefresh = (data) => {
if (data === 'date' || data === 'timezone') {
if (localStorage.getItem('date') === 'false') {
- return (this.date.current.style.display = 'none');
+ setDisplay('none');
+ return;
}
- this.date.current.style.display = 'block';
- this.date.current.style.fontSize = `${Number(
- (localStorage.getItem('zoomDate') || 100) / 100,
- )}em`;
- this.getDate();
+ setDisplay('block');
+ setFontSize(`${Number((localStorage.getItem('zoomDate') || 100) / 100)}em`);
+ getDate();
}
- });
+ };
- this.date.current.style.fontSize = `${Number(
- (localStorage.getItem('zoomDate') || 100) / 100,
- )}em`;
- this.getDate();
- }
+ setFontSize(`${Number((localStorage.getItem('zoomDate') || 100) / 100)}em`);
+ getDate();
- componentWillUnmount() {
- EventBus.off('refresh');
- }
+ EventBus.on('refresh', handleRefresh);
+ return () => {
+ EventBus.off('refresh');
+ };
+ }, []);
- render() {
- return (
-
- {this.state.date}
-
- {this.state.weekNumber}
-
- );
- }
-}
+ return (
+
+ {date}
+
+ {weekNumber}
+
+ );
+};
+
+export { DateWidget as default, DateWidget };
diff --git a/src/features/weather/Weather.jsx b/src/features/weather/Weather.jsx
index 20336c7b..d072fac5 100644
--- a/src/features/weather/Weather.jsx
+++ b/src/features/weather/Weather.jsx
@@ -1,5 +1,5 @@
import variables from 'config/variables';
-import { PureComponent } from 'react';
+import { memo, useState, useEffect, useCallback } from 'react';
import WeatherIcon from './components/WeatherIcon';
import Expanded from './components/Expanded';
@@ -11,85 +11,85 @@ import { getWeather } from './api/getWeather.js';
import './weather.scss';
-class WeatherWidget extends PureComponent {
- constructor() {
- super();
- this.state = {
- location: localStorage.getItem('location') || 'London',
- done: false,
- };
- }
+const WeatherWidget = memo(() => {
+ const [location, setLocation] = useState(localStorage.getItem('location') || 'London');
+ const [done, setDone] = useState(false);
+ const [weatherData, setWeatherData] = useState({});
- async componentDidMount() {
- EventBus.on('refresh', async (data) => {
- if (data === 'weather') {
- const weatherData = await getWeather(this.state.location, this.state.done);
- this.setState(weatherData);
-
- const zoomWeather = `${Number((localStorage.getItem('zoomWeather') || 100) / 100)}em`;
- document.querySelector('.weather').style.fontSize = zoomWeather;
- }
- });
-
- const weatherData = await getWeather(this.state.location, this.state.done);
- this.setState(weatherData);
+ const updateWeather = useCallback(async () => {
+ const data = await getWeather(location, done);
+ setWeatherData(data);
+ setDone(data.done);
const zoomWeather = `${Number((localStorage.getItem('zoomWeather') || 100) / 100)}em`;
- document.querySelector('.weather').style.fontSize = zoomWeather;
+ const weatherElement = document.querySelector('.weather');
+ if (weatherElement) {
+ weatherElement.style.fontSize = zoomWeather;
+ }
+ }, [location, done]);
+
+ useEffect(() => {
+ const handleRefresh = async (data) => {
+ if (data === 'weather') {
+ await updateWeather();
+ }
+ };
+
+ EventBus.on('refresh', handleRefresh);
+ updateWeather();
+
+ return () => {
+ EventBus.off('refresh', handleRefresh);
+ };
+ }, [updateWeather]);
+
+ const weatherType = localStorage.getItem('weatherType') || 1;
+
+ if (done === false) {
+ return
;
}
- componentWillUnmount() {
- EventBus.off('refresh');
- }
-
- render() {
- const weatherType = localStorage.getItem('weatherType') || 1;
-
- if (this.state.done === false) {
- return
;
- }
-
- if (!this.state.weather) {
- return (
-
- {this.state.location}
-
- );
- }
-
+ if (!weatherData.weather) {
return (
- {/*{this.state.done === false ?
cheese
:
loading finished
}*/}
-
-
-
-
- {`${this.state.weather.temp}${this.state.temp_text}`}
-
- {weatherType >= 2 && (
-
- {`${this.state.weather.temp_min}${this.state.temp_text}`}
- {`${this.state.weather.temp_max}${this.state.temp_text}`}
-
- )}
-
- {weatherType >= 2 && (
-
-
- {variables.getMessage('widgets.weather.feels_like', {
- amount: `${this.state.weather.feels_like}${this.state.temp_text}`,
- })}
-
- {this.state.location}
-
- )}
-
- {weatherType >= 3 && (
-
- )}
+
{location}
);
}
-}
+
+ return (
+
+
+
+
+
+ {`${weatherData.weather.temp}${weatherData.temp_text}`}
+
+ {weatherType >= 2 && (
+
+ {`${weatherData.weather.temp_min}${weatherData.temp_text}`}
+ {`${weatherData.weather.temp_max}${weatherData.temp_text}`}
+
+ )}
+
+ {weatherType >= 2 && (
+
+
+ {variables.getMessage('widgets.weather.feels_like', {
+ amount: `${weatherData.weather.feels_like}${weatherData.temp_text}`,
+ })}
+
+ {location}
+
+ )}
+
+ {weatherType >= 3 && (
+
+ )}
+
+ );
+});
+
+WeatherWidget.displayName = 'WeatherWidget';
export { WeatherWidget as default, WeatherWidget };