From 316bc49f5cc492d421f6092c11cc96f20ffbe12a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 27 May 2021 12:30:09 +0200 Subject: [PATCH] Weather settings view. API: select which keys to get from Config --- .../components/Settings/Settings.module.css | 18 ++- client/src/components/Settings/Settings.tsx | 12 +- .../WeatherSettings/WeatherSettings.tsx | 128 ++++++++++++++++++ .../UI/Forms/InputGroup/InputGroup.module.css | 4 + .../UI/Icons/WeatherIcon/WeatherIcon.tsx | 2 +- client/src/interfaces/Config.ts | 8 ++ client/src/interfaces/index.ts | 3 +- controllers/config.js | 20 ++- 8 files changed, 180 insertions(+), 15 deletions(-) create mode 100644 client/src/components/Settings/WeatherSettings/WeatherSettings.tsx create mode 100644 client/src/interfaces/Config.ts diff --git a/client/src/components/Settings/Settings.module.css b/client/src/components/Settings/Settings.module.css index 6bbd7cc..ab30bee 100644 --- a/client/src/components/Settings/Settings.module.css +++ b/client/src/components/Settings/Settings.module.css @@ -1,11 +1,10 @@ .Settings { width: 100%; display: grid; - grid-template-columns: 1fr 3fr; + grid-template-columns: 1fr; } .SettingsNav { - /* background-color: coral; */ display: flex; flex-direction: column; } @@ -19,7 +18,8 @@ transition: all 0.3s; } -.SettingsNavLink:hover { +.SettingsNavLink:hover, +.SettingsNavLink:focus { border-left: 3px solid var(--color-primary); } @@ -27,6 +27,14 @@ border-left: 3px solid var(--color-primary); } -.SettingsContent { - /* background-color:springgreen; */ +@media (min-width: 480px) { + .Settings { + grid-template-columns: 1fr 2fr; + } +} + +@media (min-width: 500px) { + .Settings { + grid-template-columns: 1fr 3fr; + } } \ No newline at end of file diff --git a/client/src/components/Settings/Settings.tsx b/client/src/components/Settings/Settings.tsx index d6406a2..81659fa 100644 --- a/client/src/components/Settings/Settings.tsx +++ b/client/src/components/Settings/Settings.tsx @@ -1,16 +1,13 @@ -import { NavLink, Link, Switch, Route, withRouter, match } from 'react-router-dom'; +import { NavLink, Link, Switch, Route, withRouter } from 'react-router-dom'; import classes from './Settings.module.css'; import { Container } from '../UI/Layout/Layout'; import Headline from '../UI/Headlines/Headline/Headline'; import Themer from '../Themer/Themer'; +import WeatherSettings from './WeatherSettings/WeatherSettings'; -interface ComponentProps { - match: match; -} - -const Settings = (props: ComponentProps): JSX.Element => { +const Settings = (): JSX.Element => { return ( { className={classes.SettingsNavLink} activeClassName={classes.SettingsNavLinkActive} exact - to='/settings/nothig'> + to='/settings/weather'> Weather
+
diff --git a/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx b/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx new file mode 100644 index 0000000..9f60ac2 --- /dev/null +++ b/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx @@ -0,0 +1,128 @@ +import { useState, ChangeEvent, Fragment, useEffect } from 'react'; +import axios from 'axios'; +import { ApiResponse, Config } from '../../../interfaces'; + +import InputGroup from '../../UI/Forms/InputGroup/InputGroup'; +import Button from '../../UI/Buttons/Button/Button'; + +interface FormState { + WEATHER_API_KEY: string; + lat: number; + long: number; + isCelsius: number; +} + +const WeatherSettings = (): JSX.Element => { + const [formData, setFormData] = useState({ + WEATHER_API_KEY: '', + lat: 0, + long: 0, + isCelsius: 1 + }) + + const inputChangeHandler = (e: ChangeEvent, isNumber?: boolean) => { + let value: string | number = e.target.value; + + if (isNumber) { + value = parseFloat(value); + } + + setFormData({ + ...formData, + [e.target.name]: value + }) + } + + useEffect(() => { + axios.get>('/api/config?keys=WEATHER_API_KEY,lat,long,isCelsius') + .then(data => { + let tmpFormData = { ...formData }; + + data.data.data.forEach((config: Config) => { + let value: string | number = config.value; + if (config.valueType === 'number') { + value = parseFloat(value); + } + + tmpFormData = { + ...tmpFormData, + [config.key]: value + } + }) + + setFormData(tmpFormData); + }) + .catch(err => console.log(err)); + }, []); + + return ( +
+ + + + inputChangeHandler(e)} + /> + + Using + + {' '}Weather API + + + + + + inputChangeHandler(e, true)} + /> + + You can use + + {' '}latlong.net + + + + + + inputChangeHandler(e, true)} + /> + + + + + + + +
+ ) +} + +export default WeatherSettings; \ No newline at end of file diff --git a/client/src/components/UI/Forms/InputGroup/InputGroup.module.css b/client/src/components/UI/Forms/InputGroup/InputGroup.module.css index bb4cc3c..6241764 100644 --- a/client/src/components/UI/Forms/InputGroup/InputGroup.module.css +++ b/client/src/components/UI/Forms/InputGroup/InputGroup.module.css @@ -26,4 +26,8 @@ .InputGroup span a { color: var(--color-accent); +} + +.InputGroup label { + color: var(--color-primary); } \ No newline at end of file diff --git a/client/src/components/UI/Icons/WeatherIcon/WeatherIcon.tsx b/client/src/components/UI/Icons/WeatherIcon/WeatherIcon.tsx index a72c6b2..6dcfe56 100644 --- a/client/src/components/UI/Icons/WeatherIcon/WeatherIcon.tsx +++ b/client/src/components/UI/Icons/WeatherIcon/WeatherIcon.tsx @@ -25,7 +25,7 @@ const WeatherIcon = (props: ComponentProps): JSX.Element => { return () => { clearTimeout(delay); } - }, []); + }, [props.weatherStatusCode]); return } diff --git a/client/src/interfaces/Config.ts b/client/src/interfaces/Config.ts new file mode 100644 index 0000000..281402c --- /dev/null +++ b/client/src/interfaces/Config.ts @@ -0,0 +1,8 @@ +import { Model } from './'; + +export interface Config extends Model { + key: string; + value: string; + valueType: string; + isLocked: boolean; +} \ No newline at end of file diff --git a/client/src/interfaces/index.ts b/client/src/interfaces/index.ts index 1daf5b4..14aece8 100644 --- a/client/src/interfaces/index.ts +++ b/client/src/interfaces/index.ts @@ -5,4 +5,5 @@ export * from './Api'; export * from './Weather'; export * from './Bookmark'; export * from './Category'; -export * from './Notification'; \ No newline at end of file +export * from './Notification'; +export * from './Config'; \ No newline at end of file diff --git a/controllers/config.js b/controllers/config.js index d73bb66..c3e2560 100644 --- a/controllers/config.js +++ b/controllers/config.js @@ -1,6 +1,7 @@ const asyncWrapper = require('../middleware/asyncWrapper'); const ErrorResponse = require('../utils/ErrorResponse'); const Config = require('../models/Config'); +const { Op } = require('sequelize'); // @desc Insert new key:value pair // @route POST /api/config @@ -16,9 +17,26 @@ exports.createPair = asyncWrapper(async (req, res, next) => { // @desc Get all key:value pairs // @route GET /api/config +// @route GET /api/config?keys=foo,bar,baz // @access Public exports.getAllPairs = asyncWrapper(async (req, res, next) => { - const pairs = await Config.findAll(); + let pairs; + + if (req.query.keys) { + // Check for specific keys to get in a single query + const keys = req.query.keys + .split(',') + .map((key) => { return { key } }); + + pairs = await Config.findAll({ + where: { + [Op.or]: keys + } + }); + } else { + // Else get all + pairs = await Config.findAll(); + } res.status(200).json({ success: true,