From 96aa1f7d6977d05d4b697b6e659c7e73f63b492a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 1 Jun 2021 14:54:47 +0200 Subject: [PATCH] Update bookmark. Changes to CSS. Changes to WeatherJob --- .../Bookmarks/BookmarkForm/BookmarkForm.tsx | 4 +- .../WeatherSettings/WeatherSettings.tsx | 21 +++++-- .../components/UI/Layout/Layout.module.css | 11 +++- .../WeatherWidget/WeatherWidget.module.css | 7 +++ .../Widgets/WeatherWidget/WeatherWidget.tsx | 57 ++++++++++++++----- client/src/index.css | 2 +- client/src/store/actions/bookmark.ts | 14 +++-- client/src/store/reducers/bookmark.ts | 32 ++++++++++- utils/Logger.js | 40 +++++++++++++ utils/getExternalWeather.js | 7 +-- utils/jobs.js | 6 +- 11 files changed, 165 insertions(+), 36 deletions(-) create mode 100644 utils/Logger.js diff --git a/client/src/components/Bookmarks/BookmarkForm/BookmarkForm.tsx b/client/src/components/Bookmarks/BookmarkForm/BookmarkForm.tsx index 4b39b14..9579b7c 100644 --- a/client/src/components/Bookmarks/BookmarkForm/BookmarkForm.tsx +++ b/client/src/components/Bookmarks/BookmarkForm/BookmarkForm.tsx @@ -17,7 +17,7 @@ interface ComponentProps { addCategory: (formData: NewCategory) => void; addBookmark: (formData: NewBookmark) => void; updateCategory: (id: number, formData: NewCategory) => void; - updateBookmark: (id: number, formData: NewBookmark) => void; + updateBookmark: (id: number, formData: NewBookmark, categoryWasChanged: boolean) => void; createNotification: (notification: NewNotification) => void; } @@ -90,7 +90,7 @@ const BookmarkForm = (props: ComponentProps): JSX.Element => { setCategoryName({ name: '' }); } else if (props.contentType === ContentType.bookmark && props.bookmark) { // Update bookmark - props.updateBookmark(props.bookmark.id, formData); + props.updateBookmark(props.bookmark.id, formData, props.bookmark.categoryId !== formData.categoryId); setFormData({ name: '', url: '', diff --git a/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx b/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx index 93ca9c7..5e1f7af 100644 --- a/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx +++ b/client/src/components/Settings/WeatherSettings/WeatherSettings.tsx @@ -1,9 +1,11 @@ -import { useState, ChangeEvent, Fragment, useEffect, FormEvent } from 'react'; +import { useState, ChangeEvent, useEffect, FormEvent } from 'react'; +import { connect } from 'react-redux'; import axios from 'axios'; -import { ApiResponse, Config } from '../../../interfaces'; +import { ApiResponse, Config, NewNotification } from '../../../interfaces'; import InputGroup from '../../UI/Forms/InputGroup/InputGroup'; import Button from '../../UI/Buttons/Button/Button'; +import { createNotification } from '../../../store/actions'; interface FormState { WEATHER_API_KEY: string; @@ -12,7 +14,11 @@ interface FormState { isCelsius: number; } -const WeatherSettings = (): JSX.Element => { +interface ComponentProps { + createNotification: (notification: NewNotification) => void; +} + +const WeatherSettings = (props: ComponentProps): JSX.Element => { const [formData, setFormData] = useState({ WEATHER_API_KEY: '', lat: 0, @@ -59,7 +65,12 @@ const WeatherSettings = (): JSX.Element => { e.preventDefault(); axios.put>('/api/config', formData) - .then(data => console.log(data.data.success)) + .then(data => { + props.createNotification({ + title: 'Success', + message: 'Settings updated' + }) + }) .catch(err => console.log(err)); } @@ -131,4 +142,4 @@ const WeatherSettings = (): JSX.Element => { ) } -export default WeatherSettings; \ No newline at end of file +export default connect(null, { createNotification })(WeatherSettings); \ No newline at end of file diff --git a/client/src/components/UI/Layout/Layout.module.css b/client/src/components/UI/Layout/Layout.module.css index 6ad351e..72d6186 100644 --- a/client/src/components/UI/Layout/Layout.module.css +++ b/client/src/components/UI/Layout/Layout.module.css @@ -1,8 +1,16 @@ .Container { width: 100%; padding: 20px; + margin: 0 auto; } +/* .Container { + width: 60%; + margin: 0 auto; + padding: 20px; + padding-top: 20px; +} */ + /* 320px — 480px: Mobile devices. 481px — 768px: iPads, Tablets. 769px — 1024px: Small screens, laptops. @@ -11,7 +19,8 @@ @media (min-width: 769px) { .Container { - padding: 25px 40px; + /* padding: 25px 40px; */ + width: 90%; } } diff --git a/client/src/components/Widgets/WeatherWidget/WeatherWidget.module.css b/client/src/components/Widgets/WeatherWidget/WeatherWidget.module.css index e13f5ab..04dd8ef 100644 --- a/client/src/components/Widgets/WeatherWidget/WeatherWidget.module.css +++ b/client/src/components/Widgets/WeatherWidget/WeatherWidget.module.css @@ -1,5 +1,6 @@ .WeatherWidget { display: flex; + visibility: hidden; } .WeatherDetails { @@ -19,4 +20,10 @@ .WeatherDetails span:last-child { padding-top: 5px; +} + +@media (min-width: 600px) { + .WeatherWidget { + visibility: visible; + } } \ No newline at end of file diff --git a/client/src/components/Widgets/WeatherWidget/WeatherWidget.tsx b/client/src/components/Widgets/WeatherWidget/WeatherWidget.tsx index 67fa7fe..1872089 100644 --- a/client/src/components/Widgets/WeatherWidget/WeatherWidget.tsx +++ b/client/src/components/Widgets/WeatherWidget/WeatherWidget.tsx @@ -14,38 +14,65 @@ const WeatherWidget = (): JSX.Element => { isDay: 1, conditionText: '', conditionCode: 1000, - id: 0, + id: -1, createdAt: new Date(), updatedAt: new Date() }); const [isLoading, setIsLoading] = useState(true); + // Initial request to get data useEffect(() => { axios.get>('/api/weather') .then(data => { - setWeather(data.data.data[0]); + const weatherData = data.data.data[0]; + if (weatherData) { + setWeather(weatherData); + } setIsLoading(false); }) .catch(err => console.log(err)); }, []); + // Open socket for data updates + useEffect(() => { + const webSocketClient = new WebSocket('ws://localhost:5005'); + + webSocketClient.onopen = () => { + console.log('WebSocket opened'); + } + + webSocketClient.onclose = () => { + console.log('WebSocket closed') + } + + webSocketClient.onmessage = (e) => { + const data = JSON.parse(e.data); + setWeather({ + ...weather, + ...data + }) + } + + return () => webSocketClient.close(); + }, []); + return (
{isLoading ? 'loading' - : ( - -
- -
-
- {weather.tempC}°C - {weather.conditionCode} -
-
+ : (weather.id > 0 && + ( +
+ +
+
+ {weather.tempC}°C + {weather.conditionCode} +
+
) ) }
diff --git a/client/src/index.css b/client/src/index.css index 4f64f2a..2662dab 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -2,7 +2,7 @@ margin: 0; padding: 0; box-sizing: border-box; - user-select: none; + /* user-select: none; */ } body { diff --git a/client/src/store/actions/bookmark.ts b/client/src/store/actions/bookmark.ts index 013846b..f65eec2 100644 --- a/client/src/store/actions/bookmark.ts +++ b/client/src/store/actions/bookmark.ts @@ -218,13 +218,16 @@ export const deleteBookmark = (bookmarkId: number, categoryId: number) => async */ export interface UpdateBookmarkAction { type: ActionTypes.updateBookmark, - payload: Bookmark + payload: { + bookmark: Bookmark, + categoryWasChanged: boolean + } } -export const updateBookmark = (bookmarkId: number, formData: NewBookmark) => async (dispatch: Dispatch) => { +export const updateBookmark = (bookmarkId: number, formData: NewBookmark, categoryWasChanged: boolean) => async (dispatch: Dispatch) => { try { const res = await axios.put>(`/api/bookmarks/${bookmarkId}`, formData); - + dispatch({ type: ActionTypes.createNotification, payload: { @@ -235,7 +238,10 @@ export const updateBookmark = (bookmarkId: number, formData: NewBookmark) => asy dispatch({ type: ActionTypes.updateBookmark, - payload: res.data.data + payload: { + bookmark: res.data.data, + categoryWasChanged + } }) } catch (err) { console.log(err); diff --git a/client/src/store/reducers/bookmark.ts b/client/src/store/reducers/bookmark.ts index d650a1a..b39abbb 100644 --- a/client/src/store/reducers/bookmark.ts +++ b/client/src/store/reducers/bookmark.ts @@ -107,8 +107,38 @@ const deleteBookmark = (state: State, action: Action): State => { } const updateBookmark = (state: State, action: Action): State => { + const { bookmark, categoryWasChanged } = action.payload; + const tmpCategories = [...state.categories]; + + let categoryIndex = state.categories.findIndex((category: Category) => category.id === bookmark.categoryId); + let bookmarkIndex = state.categories[categoryIndex].bookmarks.findIndex((bookmark: Bookmark) => bookmark.id === bookmark.id); + + // if (categoryWasChanged) { + // const categoryInUpdate = tmpCategories.find((category: Category) => category.id === bookmark.categoryId); + + // if (categoryInUpdate) { + // categoryInUpdate.bookmarks = categoryInUpdate.bookmarks.filter((_bookmark: Bookmark) => _bookmark.id === bookmark.id); + // } + + // console.log(categoryInUpdate); + // } + return { - ...state + ...state, + categories: [ + ...state.categories.slice(0, categoryIndex), + { + ...state.categories[categoryIndex], + bookmarks: [ + ...state.categories[categoryIndex].bookmarks.slice(0, bookmarkIndex), + { + ...bookmark + }, + ...state.categories[categoryIndex].bookmarks.slice(bookmarkIndex + 1) + ] + }, + ...state.categories.slice(categoryIndex + 1) + ] } } diff --git a/utils/Logger.js b/utils/Logger.js new file mode 100644 index 0000000..6301dfe --- /dev/null +++ b/utils/Logger.js @@ -0,0 +1,40 @@ +const fs = require('fs'); + +class Logger { + constructor() { + this.logFileHandler(); + } + + logFileHandler() { + if (!fs.existsSync('./flame.log')) { + fs.writeFileSync('./flame.log', ''); + } else { + console.log('file exists'); + } + } + + writeLog(logMsg, logType) { + + } + + generateLog(logMsg, logType) { + const now = new Date(); + const date = `${this.parseNumber(now.getDate())}-${this.parseNumber(now.getMonth() + 1)}-${now.getFullYear()}`; + const time = `${this.parseNumber(now.getHours())}:${this.parseNumber(now.getMinutes())}:${this.parseNumber(now.getSeconds())}.${now.getMilliseconds()}`; + const log = `[${date} ${time}]: ${logType} ${logMsg}`; + return log; + // const timestamp = new Date().toISOString(); + } + + parseNumber(number) { + if (number > 9) { + return number; + } else { + return `0${number}`; + } + } +} + +// console.log(logger.generateLog('testMsg', 'INFO')); + +module.exports = new Logger(); \ No newline at end of file diff --git a/utils/getExternalWeather.js b/utils/getExternalWeather.js index b36d825..bda234f 100644 --- a/utils/getExternalWeather.js +++ b/utils/getExternalWeather.js @@ -30,7 +30,7 @@ const getExternalWeather = async () => { // Save weather data const cursor = res.data.current; - await Weather.create({ + const weatherData = await Weather.create({ externalLastUpdate: cursor.last_updated, tempC: cursor.temp_c, tempF: cursor.temp_f, @@ -38,10 +38,9 @@ const getExternalWeather = async () => { conditionText: cursor.condition.text, conditionCode: cursor.condition.code }); + return weatherData; } catch (err) { - console.log(err); - console.log('External API request failed'); - return; + throw new Error('External API request failed'); } } diff --git a/utils/jobs.js b/utils/jobs.js index 4c4747e..bb2670c 100644 --- a/utils/jobs.js +++ b/utils/jobs.js @@ -4,10 +4,10 @@ const Sockets = require('../Sockets'); const weatherJob = schedule.scheduleJob('updateWeather', '0 */15 * * * *', async () => { try { - await getExternalWeather(); + const weatherData = await getExternalWeather(); console.log('weather updated'); - Sockets.getSocket('weather').socket.send('weather updated'); + Sockets.getSocket('weather').socket.send(JSON.stringify(weatherData)); } catch (err) { - console.log(err); + console.log(err.message); } }) \ No newline at end of file