From bc0abd4ee0c2f77f33003037bb3d5f69c2d2272d Mon Sep 17 00:00:00 2001 From: violetadev Date: Sat, 21 Sep 2024 14:32:31 +0200 Subject: [PATCH] notification component --- desktop-app/src/common/constants.ts | 7 ++ desktop-app/src/main/main.ts | 4 ++ .../components/Notifications/Notification.tsx | 33 ++++++++++ .../Notifications/NotificationEmptyStatus.tsx | 9 +++ .../Notifications/Notifications.tsx | 27 ++++++++ .../Notifications/NotificationsBubble.tsx | 10 +++ .../components/Previewer/Device/Toolbar.tsx | 22 ++++++- .../components/ToolBar/Menu/Flyout/index.tsx | 14 ++-- .../components/ToolBar/Menu/index.tsx | 15 ++++- .../src/renderer/components/ToolBar/index.tsx | 3 +- .../useCheckVersion/useCheckVersion.tsx | 64 +++++++++++++++++++ .../useLocalStorage/useLocalStorage.tsx | 44 +++++++++++++ .../renderer/store/features/renderer/index.ts | 16 +++++ 13 files changed, 254 insertions(+), 14 deletions(-) create mode 100644 desktop-app/src/renderer/components/Notifications/Notification.tsx create mode 100644 desktop-app/src/renderer/components/Notifications/NotificationEmptyStatus.tsx create mode 100644 desktop-app/src/renderer/components/Notifications/Notifications.tsx create mode 100644 desktop-app/src/renderer/components/Notifications/NotificationsBubble.tsx create mode 100644 desktop-app/src/renderer/components/useCheckVersion/useCheckVersion.tsx create mode 100644 desktop-app/src/renderer/components/useLocalStorage/useLocalStorage.tsx diff --git a/desktop-app/src/common/constants.ts b/desktop-app/src/common/constants.ts index 6a04890c3..e4dd3d361 100644 --- a/desktop-app/src/common/constants.ts +++ b/desktop-app/src/common/constants.ts @@ -16,6 +16,13 @@ export const PREVIEW_LAYOUTS = { export type PreviewLayout = typeof PREVIEW_LAYOUTS[keyof typeof PREVIEW_LAYOUTS]; +export type Notification = { + id: string; + link?: string; + linkText?: string; + text: string; +}; + export interface OpenUrlArgs { url: string; } diff --git a/desktop-app/src/main/main.ts b/desktop-app/src/main/main.ts index e4f8084b7..494fa57fb 100644 --- a/desktop-app/src/main/main.ts +++ b/desktop-app/src/main/main.ts @@ -263,6 +263,10 @@ const createWindow = async () => { ipcMain.on('stop-watcher', async () => { await stopWatchFiles(); }); + + ipcMain.handle('get-app-version', () => { + return app.getVersion(); + }); }; app.on('open-url', async (event, url) => { diff --git a/desktop-app/src/renderer/components/Notifications/Notification.tsx b/desktop-app/src/renderer/components/Notifications/Notification.tsx new file mode 100644 index 000000000..97f374eb6 --- /dev/null +++ b/desktop-app/src/renderer/components/Notifications/Notification.tsx @@ -0,0 +1,33 @@ +import { + IPC_MAIN_CHANNELS, + Notification as NotificationType, +} from 'common/constants'; +import Button from '../Button'; + +const Notification = ({ notification }: { notification: NotificationType }) => { + const handleLinkClick = (url: string) => { + window.electron.ipcRenderer.sendMessage(IPC_MAIN_CHANNELS.OPEN_EXTERNAL, { + url, + }); + }; + + return ( +
+

{notification.text}

+ {notification.link && notification.linkText && ( + + )} +
+ ); +}; + +export default Notification; diff --git a/desktop-app/src/renderer/components/Notifications/NotificationEmptyStatus.tsx b/desktop-app/src/renderer/components/Notifications/NotificationEmptyStatus.tsx new file mode 100644 index 000000000..c6830dbb3 --- /dev/null +++ b/desktop-app/src/renderer/components/Notifications/NotificationEmptyStatus.tsx @@ -0,0 +1,9 @@ +const NotificationEmptyStatus = () => { + return ( +
+

You are all caught up! No new notifications at the moment.

+
+ ); +}; + +export default NotificationEmptyStatus; diff --git a/desktop-app/src/renderer/components/Notifications/Notifications.tsx b/desktop-app/src/renderer/components/Notifications/Notifications.tsx new file mode 100644 index 000000000..c5835ce7d --- /dev/null +++ b/desktop-app/src/renderer/components/Notifications/Notifications.tsx @@ -0,0 +1,27 @@ +import { useSelector } from 'react-redux'; +import { selectNotifications } from 'renderer/store/features/renderer'; +import { v4 as uuidv4 } from 'uuid'; +import { Notification as NotificationType } from 'common/constants'; +import Notification from './Notification'; +import NotificationEmptyStatus from './NotificationEmptyStatus'; + +const Notifications = () => { + const notificationsState = useSelector(selectNotifications); + + return ( +
+ Notifications +
+ {(!notificationsState || notificationsState?.length === 0) && ( + + )} + {notificationsState?.length > 0 && + notificationsState?.map((notification: NotificationType) => ( + + ))} +
+
+ ); +}; + +export default Notifications; diff --git a/desktop-app/src/renderer/components/Notifications/NotificationsBubble.tsx b/desktop-app/src/renderer/components/Notifications/NotificationsBubble.tsx new file mode 100644 index 000000000..43dc1cb29 --- /dev/null +++ b/desktop-app/src/renderer/components/Notifications/NotificationsBubble.tsx @@ -0,0 +1,10 @@ +const NotificationsBubble = () => { + return ( + + + + + ); +}; + +export default NotificationsBubble; diff --git a/desktop-app/src/renderer/components/Previewer/Device/Toolbar.tsx b/desktop-app/src/renderer/components/Previewer/Device/Toolbar.tsx index 41a950e08..1b4a56640 100644 --- a/desktop-app/src/renderer/components/Previewer/Device/Toolbar.tsx +++ b/desktop-app/src/renderer/components/Previewer/Device/Toolbar.tsx @@ -1,5 +1,5 @@ import { Icon } from '@iconify/react'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import Button from 'renderer/components/Button'; import useSound from 'use-sound'; import { ScreenshotArgs, ScreenshotResult } from 'main/screenshot'; @@ -8,6 +8,9 @@ import WebPage from 'main/screenshot/webpage'; import screenshotSfx from 'renderer/assets/sfx/screenshot.mp3'; import { updateWebViewHeightAndScale } from 'common/webViewUtils'; +import useCheckVersion from 'renderer/components/useCheckVersion/useCheckVersion'; +import { useDispatch } from 'react-redux'; +import { setNotifications } from 'renderer/store/features/renderer'; import { ColorBlindnessTools } from './ColorBlindnessTools'; interface Props { @@ -21,6 +24,13 @@ interface Props { isIndividualLayout: boolean; } +const newVersionText = { + id: 'new-version', + text: 'There is a new version available.', + link: 'https://responsively.app/download', + linkText: 'See More', +}; + const Toolbar = ({ webview, device, @@ -38,6 +48,16 @@ const Toolbar = ({ useState(false); const [rotated, setRotated] = useState(false); + const dispatch = useDispatch(); + + const { isNewVersionAvailable } = useCheckVersion(); + + useEffect(() => { + if (isNewVersionAvailable) { + dispatch(setNotifications(newVersionText)); + } + }, [dispatch, isNewVersionAvailable]); + const refreshView = () => { if (webview) { webview.reload(); diff --git a/desktop-app/src/renderer/components/ToolBar/Menu/Flyout/index.tsx b/desktop-app/src/renderer/components/ToolBar/Menu/Flyout/index.tsx index a4ac6d3ac..c707105b8 100644 --- a/desktop-app/src/renderer/components/ToolBar/Menu/Flyout/index.tsx +++ b/desktop-app/src/renderer/components/ToolBar/Menu/Flyout/index.tsx @@ -1,8 +1,6 @@ -import { useDispatch } from 'react-redux'; - -import Button from 'renderer/components/Button'; -import { APP_VIEWS, setAppView } from 'renderer/store/features/ui'; import MasonryLayout from 'renderer/components/Masonry/MasonryLayout'; +import Notifications from 'renderer/components/Notifications/Notifications'; +import { Divider } from 'renderer/components/Divider'; import Devtools from './Devtools'; import UITheme from './UITheme'; import Zoom from './Zoom'; @@ -12,17 +10,11 @@ import PreviewLayout from './PreviewLayout'; import Bookmark from './Bookmark'; import { Settings } from './Settings'; -const Divider = () => ( -
-); - interface Props { closeFlyout: () => void; } const MenuFlyout = ({ closeFlyout }: Props) => { - const dispatch = useDispatch(); - return (
@@ -38,6 +30,8 @@ const MenuFlyout = ({ closeFlyout }: Props) => {
+ +
); }; diff --git a/desktop-app/src/renderer/components/ToolBar/Menu/index.tsx b/desktop-app/src/renderer/components/ToolBar/Menu/index.tsx index ddafa6f42..f2e2ac1cf 100644 --- a/desktop-app/src/renderer/components/ToolBar/Menu/index.tsx +++ b/desktop-app/src/renderer/components/ToolBar/Menu/index.tsx @@ -3,11 +3,20 @@ import { useDetectClickOutside } from 'react-detect-click-outside'; import Button from 'renderer/components/Button'; import { useDispatch, useSelector } from 'react-redux'; import { closeMenuFlyout, selectMenuFlyout } from 'renderer/store/features/ui'; +import { selectNotifications } from 'renderer/store/features/renderer'; +import useLocalStorage from 'renderer/components/useLocalStorage/useLocalStorage'; +import NotificationsBubble from 'renderer/components/Notifications/NotificationsBubble'; import MenuFlyout from './Flyout'; const Menu = () => { const dispatch = useDispatch(); const isMenuFlyoutOpen = useSelector(selectMenuFlyout); + const notifications = useSelector(selectNotifications); + + const [hasNewNotifications, setHasNewNotifications] = useLocalStorage( + 'hasNewNotifications', + true + ); const ref = useDetectClickOutside({ onTriggered: () => { @@ -20,6 +29,7 @@ const Menu = () => { const handleFlyout = () => { dispatch(closeMenuFlyout(!isMenuFlyoutOpen)); + setHasNewNotifications(false); }; const onClose = () => { @@ -27,9 +37,12 @@ const Menu = () => { }; return ( -
+
diff --git a/desktop-app/src/renderer/components/ToolBar/index.tsx b/desktop-app/src/renderer/components/ToolBar/index.tsx index 9a8d0c857..51739039c 100644 --- a/desktop-app/src/renderer/components/ToolBar/index.tsx +++ b/desktop-app/src/renderer/components/ToolBar/index.tsx @@ -6,6 +6,7 @@ import { setIsCapturingScreenshot, setIsInspecting, setRotate, + setNotifications, } from 'renderer/store/features/renderer'; import { Icon } from '@iconify/react'; import { ScreenshotAllArgs } from 'main/screenshot'; @@ -103,9 +104,7 @@ const ToolBar = () => { return (
- -