refactor: weather and app to functional components

This commit is contained in:
alexsparkes
2024-05-29 16:44:40 +01:00
parent 4def9db23f
commit e7482e8fe6
2 changed files with 242 additions and 236 deletions

View File

@@ -1,56 +1,75 @@
import variables from 'config/variables';
import { PureComponent } from 'react';
import { useEffect, useState } from 'react';
import { ToastContainer } from 'react-toastify';
import Background from 'features/background/Background';
import Widgets from 'features/misc/views/Widgets';
import Modals from 'features/misc/modals/Modals';
import { loadSettings, moveSettings } from 'utils/settings';
import EventBus from 'utils/eventbus';
import variables from 'config/variables';
export default class App extends PureComponent {
componentDidMount() {
// 4.0 -> 5.0 (the key below is only on 5.0)
// now featuring 5.0 -> 5.1
// the firstRun check was moved here because the old function was useless
if (!localStorage.getItem('firstRun') || !localStorage.getItem('stats')) {
const useAppSetup = () => {
useEffect(() => {
const firstRun = localStorage.getItem('firstRun');
const stats = localStorage.getItem('stats');
if (!firstRun || !stats) {
moveSettings();
window.location.reload();
}
loadSettings();
EventBus.on('refresh', (data) => {
const refreshHandler = (data) => {
if (data === 'other') {
loadSettings(true);
}
});
};
EventBus.on('refresh', refreshHandler);
variables.stats.tabLoad();
}
componentWillUnmount() {
EventBus.off('refresh');
}
return () => {
EventBus.off('refresh', refreshHandler);
};
}, []);
};
render() {
return (
<>
{localStorage.getItem('background') === 'true' && <Background />}
<ToastContainer
position="top-center"
autoClose={localStorage.getItem('toastDisplayTime') || 2500}
newestOnTop={true}
closeOnClick
pauseOnFocusLoss
/>
<div id="center">
<Widgets />
<Modals />
</div>
</>
);
}
}
const App = () => {
const [toastDisplayTime, setToastDisplayTime] = useState(2500);
const [showBackground, setShowBackground] = useState(false);
useEffect(() => {
const storedToastDisplayTime = localStorage.getItem('toastDisplayTime');
const storedBackground = localStorage.getItem('background');
if (storedToastDisplayTime) {
setToastDisplayTime(parseInt(storedToastDisplayTime, 10));
}
if (storedBackground === 'true') {
setShowBackground(true);
}
}, []);
useAppSetup();
return (
<>
{showBackground && <Background />}
<ToastContainer
position="top-center"
autoClose={toastDisplayTime}
newestOnTop={true}
closeOnClick
pauseOnFocusLoss
/>
<div id="center">
<Widgets />
<Modals />
</div>
</>
);
};
export default App;

View File

@@ -1,224 +1,211 @@
import variables from 'config/variables';
import { PureComponent } from 'react';
import { useState, useEffect, useCallback } from 'react';
import { MdAutoAwesome } from 'react-icons/md';
import { Header, Row, Content, Action, PreferencesWrapper } from 'components/Layout/Settings';
import { Radio, Dropdown, Checkbox } from 'components/Form/Settings';
import { TextField } from '@mui/material';
import variables from 'config/variables';
class WeatherOptions extends PureComponent {
constructor() {
super();
this.state = {
location: localStorage.getItem('location') || '',
windSpeed: localStorage.getItem('windspeed') !== 'true',
};
}
const useLocalStorageState = (key, initialValue) => {
const [state, setState] = useState(() => localStorage.getItem(key) || initialValue);
componentDidUpdate() {
localStorage.setItem('location', this.state.location);
}
useEffect(() => {
localStorage.setItem(key, state);
}, [key, state]);
showReminder() {
return [state, setState];
};
const useWeatherSettings = () => {
const [location, setLocation] = useLocalStorageState('location', '');
const [windSpeed, setWindSpeed] = useLocalStorageState('windspeed', 'true');
const showReminder = useCallback(() => {
document.querySelector('.reminder-info').style.display = 'flex';
localStorage.setItem('showReminder', true);
}
}, []);
changeLocation(e) {
const changeLocation = (e) => {
localStorage.removeItem('currentWeather');
this.setState({
location: e.target.value,
});
setLocation(e.target.value);
showReminder();
};
this.showReminder();
}
const getAutoLocation = useCallback(() => {
setLocation(variables.getMessage('modals.main.loading'));
render() {
const weatherType = localStorage.getItem('weatherType');
const WEATHER_SECTION = 'modals.main.settings.sections.weather';
navigator.geolocation.getCurrentPosition(
async (position) => {
const data = await (
await fetch(
`${variables.constants.API_URL}/gps?latitude=${position.coords.latitude}&longitude=${position.coords.longitude}`
)
).json();
setLocation(data[0].name);
showReminder();
},
(error) => {
console.error(error);
},
{
enableHighAccuracy: true,
}
);
}, [setLocation, showReminder]);
const WidgetType = () => {
return (
<Row>
<Content title={variables.getMessage(`${WEATHER_SECTION}.widget_type`)} />
<Action>
<Dropdown
label={variables.getMessage('modals.main.settings.sections.time.type')}
name="weatherType"
category="weather"
onChange={() => this.forceUpdate()}
items={[
{ value: '1', text: variables.getMessage(`${WEATHER_SECTION}.options.basic`) },
{
value: '2',
text: variables.getMessage(`${WEATHER_SECTION}.options.standard`),
},
{
value: '3',
text: variables.getMessage(`${WEATHER_SECTION}.options.expanded`),
},
{ value: '4', text: variables.getMessage(`${WEATHER_SECTION}.options.custom`) },
]}
/>
</Action>
</Row>
);
};
return {
location,
windSpeed: windSpeed !== 'true',
setWindSpeed,
changeLocation,
getAutoLocation,
};
};
const LocationSetting = () => {
const getAuto = () => {
this.setState({
location: variables.getMessage('modals.main.loading'),
});
const WeatherOptions = () => {
const { location, windSpeed, setWindSpeed, changeLocation, getAutoLocation } = useWeatherSettings();
const weatherType = localStorage.getItem('weatherType');
const WEATHER_SECTION = 'modals.main.settings.sections.weather';
navigator.geolocation.getCurrentPosition(
async (position) => {
const data = await (
await fetch(
`${variables.constants.API_URL}/gps?latitude=${position.coords.latitude}&longitude=${position.coords.longitude}`,
)
).json();
this.setState({
location: data[0].name,
});
const WidgetType = () => (
<Row>
<Content title={variables.getMessage(`${WEATHER_SECTION}.widget_type`)} />
<Action>
<Dropdown
label={variables.getMessage('modals.main.settings.sections.time.type')}
name="weatherType"
category="weather"
onChange={() => this.forceUpdate()}
items={[
{ value: '1', text: variables.getMessage(`${WEATHER_SECTION}.options.basic`) },
{ value: '2', text: variables.getMessage(`${WEATHER_SECTION}.options.standard`) },
{ value: '3', text: variables.getMessage(`${WEATHER_SECTION}.options.expanded`) },
{ value: '4', text: variables.getMessage(`${WEATHER_SECTION}.options.custom`) },
]}
/>
</Action>
</Row>
);
this.showReminder();
},
(error) => {
// firefox requires this 2nd function
console.error(error);
},
{
enableHighAccuracy: true,
},
);
};
return (
<Row>
<Content title={variables.getMessage(`${WEATHER_SECTION}.location`)} />
<Action>
<TextField
label={variables.getMessage(`${WEATHER_SECTION}.location`)}
value={this.state.location}
onChange={(e) => this.changeLocation(e)}
placeholder="London"
varient="outlined"
InputLabelProps={{ shrink: true }}
/>
<span className="link" onClick={getAuto}>
<MdAutoAwesome />
{variables.getMessage(`${WEATHER_SECTION}.auto`)}
</span>
</Action>
</Row>
);
};
const LocationSetting = () => (
<Row>
<Content title={variables.getMessage(`${WEATHER_SECTION}.location`)} />
<Action>
<TextField
label={variables.getMessage(`${WEATHER_SECTION}.location`)}
value={location}
onChange={changeLocation}
placeholder="London"
variant="outlined"
InputLabelProps={{ shrink: true }}
/>
<span className="link" onClick={getAutoLocation}>
<MdAutoAwesome />
{variables.getMessage(`${WEATHER_SECTION}.auto`)}
</span>
</Action>
</Row>
);
const TemperatureFormat = () => {
return (
<Row final={weatherType !== '4'}>
<Content title={variables.getMessage(`${WEATHER_SECTION}.temp_format.title`)} />
<Action>
<Radio
name="tempformat"
options={[
{
name: variables.getMessage(`${WEATHER_SECTION}.temp_format.celsius`) + ' (°C)',
value: 'celsius',
},
{
name: variables.getMessage(`${WEATHER_SECTION}.temp_format.fahrenheit`) + ' (°F)',
value: 'fahrenheit',
},
{
name: variables.getMessage(`${WEATHER_SECTION}.temp_format.kelvin`) + ' (K)',
value: 'kelvin',
},
]}
category="weather"
/>
</Action>
</Row>
);
};
const TemperatureFormat = () => (
<Row final={weatherType !== '4'}>
<Content title={variables.getMessage(`${WEATHER_SECTION}.temp_format.title`)} />
<Action>
<Radio
name="tempformat"
options={[
{
name: `${variables.getMessage(`${WEATHER_SECTION}.temp_format.celsius`)} (°C)`,
value: 'celsius',
},
{
name: `${variables.getMessage(`${WEATHER_SECTION}.temp_format.fahrenheit`)} (°F)`,
value: 'fahrenheit',
},
{
name: `${variables.getMessage(`${WEATHER_SECTION}.temp_format.kelvin`)} (K)`,
value: 'kelvin',
},
]}
category="weather"
/>
</Action>
</Row>
);
const CustomOptions = () => {
const weatherOptions = [
{
name: 'weatherdescription',
textKey: `${WEATHER_SECTION}.extra_info.show_description`,
},
{
name: 'cloudiness',
textKey: `${WEATHER_SECTION}.extra_info.cloudiness`,
},
{ name: 'humidity', textKey: `${WEATHER_SECTION}.extra_info.humidity` },
{
name: 'visibility',
textKey: `${WEATHER_SECTION}.extra_info.visibility`,
},
{
name: 'windspeed',
textKey: `${WEATHER_SECTION}.extra_info.wind_speed`,
onChange: () =>
this.setState({ windSpeed: localStorage.getItem('windspeed') !== 'true' }),
},
{
name: 'windDirection',
textKey: `${WEATHER_SECTION}.extra_info.wind_direction`,
disabled: this.state.windSpeed,
},
{
name: 'atmosphericpressure',
textKey: `${WEATHER_SECTION}.extra_info.atmospheric_pressure`,
},
];
return (
<Row final={true}>
<Content title={variables.getMessage(`${WEATHER_SECTION}.custom_settings`)} />
<Action>
{weatherOptions.map((item) => (
<Checkbox
key={item.name}
name={item.name}
text={variables.getMessage(item.textKey)}
category="weather"
onChange={item.onChange}
disabled={item.disabled}
/>
))}
</Action>
</Row>
);
};
const CustomOptions = () => {
const weatherOptions = [
{
name: 'weatherdescription',
textKey: `${WEATHER_SECTION}.extra_info.show_description`,
},
{
name: 'cloudiness',
textKey: `${WEATHER_SECTION}.extra_info.cloudiness`,
},
{ name: 'humidity', textKey: `${WEATHER_SECTION}.extra_info.humidity` },
{
name: 'visibility',
textKey: `${WEATHER_SECTION}.extra_info.visibility`,
},
{
name: 'windspeed',
textKey: `${WEATHER_SECTION}.extra_info.wind_speed`,
onChange: () => setWindSpeed(localStorage.getItem('windspeed') !== 'true'),
},
{
name: 'windDirection',
textKey: `${WEATHER_SECTION}.extra_info.wind_direction`,
disabled: windSpeed,
},
{
name: 'atmosphericpressure',
textKey: `${WEATHER_SECTION}.extra_info.atmospheric_pressure`,
},
];
return (
<>
<Header
title={variables.getMessage(`${WEATHER_SECTION}.title`)}
setting="weatherEnabled"
category="widgets"
zoomSetting="zoomWeather"
zoomCategory="weather"
visibilityToggle={true}
/>
<PreferencesWrapper
setting="weatherEnabled"
zoomSetting="zoomWeather"
zoomCategory="weather"
visibilityToggle={true}
>
<WidgetType />
{/* https://stackoverflow.com/a/65328486 when using inputs it may defocus so we do the {} instead of <> */}
{LocationSetting()}
<TemperatureFormat />
{weatherType === '4' && <CustomOptions />}
</PreferencesWrapper>
</>
<Row final={true}>
<Content title={variables.getMessage(`${WEATHER_SECTION}.custom_settings`)} />
<Action>
{weatherOptions.map((item) => (
<Checkbox
key={item.name}
name={item.name}
text={variables.getMessage(item.textKey)}
category="weather"
onChange={item.onChange}
disabled={item.disabled}
/>
))}
</Action>
</Row>
);
}
}
};
return (
<>
<Header
title={variables.getMessage(`${WEATHER_SECTION}.title`)}
setting="weatherEnabled"
category="widgets"
zoomSetting="zoomWeather"
zoomCategory="weather"
visibilityToggle={true}
/>
<PreferencesWrapper
setting="weatherEnabled"
zoomSetting="zoomWeather"
zoomCategory="weather"
visibilityToggle={true}
>
<WidgetType />
{/* https://stackoverflow.com/a/65328486 when using inputs it may defocus so we do the {} instead of <> */}
{LocationSetting()}
<TemperatureFormat />
{weatherType === '4' && <CustomOptions />}
</PreferencesWrapper>
</>
);
};
export { WeatherOptions as default, WeatherOptions };