From 5beefdb1292f85252c5708fc053103d4e3c91507 Mon Sep 17 00:00:00 2001 From: vishal-codes Date: Tue, 2 May 2023 00:16:07 +0530 Subject: [PATCH 1/2] feat: install pwa, share & fix cloud bug Signed-off-by: vishal-codes --- client/public/index.html | 16 +- client/public/manifest.json | 36 ++- client/public/serviceWorker.js | 41 +++ client/src/components/home/HomeLeftSide.js | 280 ++++++++++--------- client/src/components/home/HomeMenu.js | 262 +++++++++-------- client/src/components/home/HomeRightSide.js | 11 +- client/src/components/workspace/SideStrip.js | 25 +- client/src/components/workspace/WorkSpace.js | 1 - 8 files changed, 398 insertions(+), 274 deletions(-) create mode 100644 client/public/serviceWorker.js diff --git a/client/public/index.html b/client/public/index.html index 62e6a24..804967e 100644 --- a/client/public/index.html +++ b/client/public/index.html @@ -60,5 +60,19 @@ To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. - --> + --> + + diff --git a/client/public/manifest.json b/client/public/manifest.json index 080d6c7..c5046d1 100644 --- a/client/public/manifest.json +++ b/client/public/manifest.json @@ -1,25 +1,33 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "theme_color": "#1976d2", + "background_color": "#000", + "display": "standalone", + "scope": "/", + "start_url": "/", + "name": "Dev Chat+", + "short_name": "Dev Chat+", + "description": "DevChat+ is a great productivity tool that combines all the awesome features of video-calling with useful tools such as whiteboarding and a built in IDE to help you get your point across.", "icons": [ { "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", + "sizes": "32x32", "type": "image/x-icon" }, { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" + "src": "/logo192.png", + "sizes": "192x192", + "type": "image/png" }, { - "src": "logo512.png", + "src": "/assets/icons/maskable_icon_x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "/assets/icons/maskable_icon_x512.png", + "sizes": "512x512", "type": "image/png", - "sizes": "512x512" + "purpose": "maskable" } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} + ] +} \ No newline at end of file diff --git a/client/public/serviceWorker.js b/client/public/serviceWorker.js new file mode 100644 index 0000000..a3ac599 --- /dev/null +++ b/client/public/serviceWorker.js @@ -0,0 +1,41 @@ +const CACHE_NAME = 'version-1.0'; +const urlsToCache = ['index.html', 'offline.html']; + +const self = this; + +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME).then((cache) => { + // eslint-disable-next-line no-console + console.log('Opened cache'); + return cache.addAll(urlsToCache); + }) + ); +}); + +self.addEventListener('fetch', (event) => { + event.respondWith( + caches.match(event.request).then(() => { + return fetch(event.request).catch(() => + caches.match('offline.html') + ); + }) + ); +}); + +self.addEventListener('activate', (event) => { + const cacheWhitelist = []; + cacheWhitelist.push(CACHE_NAME); + + event.waitUntil( + caches.keys().then((cacheNames) => + Promise.all( + cacheNames.map((cacheName) => { + if (!cacheWhitelist.includes(cacheName)) { + return caches.delete(cacheName); + } + }) + ) + ) + ); +}); diff --git a/client/src/components/home/HomeLeftSide.js b/client/src/components/home/HomeLeftSide.js index 32bff9d..c2c2ae8 100644 --- a/client/src/components/home/HomeLeftSide.js +++ b/client/src/components/home/HomeLeftSide.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import Box from '@mui/material/Box'; import Drawer from '@mui/material/Drawer'; @@ -18,147 +18,163 @@ import HomeMenu from './HomeMenu'; const drawerWidth = 470; export default function HomeLeftSide({ - themeChange, - mode, - currentUser, - chat, - setChat, + themeChange, + mode, + currentUser, + chat, + setChat, }) { - const dispatch = useDispatch(); + const dispatch = useDispatch(); - const [notificationGranted, setNotificationGranted] = useState( - Notification.permission === 'granted' - ); + const [notificationGranted, setNotificationGranted] = useState( + Notification.permission === 'granted' + ); - const [modalOpen, setModalOpen] = useState(false); - const [senderid, setSenderid] = useState(''); + const [modalOpen, setModalOpen] = useState(false); + const [senderid, setSenderid] = useState(''); + const [supportsPWA, setSupportsPWA] = useState(false); + const [promptInstall, setPromptInstall] = useState(null); + useEffect(() => { + const handler = (e) => { + e.preventDefault(); + setSupportsPWA(true); + setPromptInstall(e); + }; + window.addEventListener('beforeinstallprompt', handler); + }, []); - useEffect(() => { - const unsub2 = onSnapshot(collection(db, 'chats'), (snapshot) => { - snapshot.docChanges().forEach((change) => { - if (change.type === 'modified') { - const modifiedData = change.doc.data(); - const length = modifiedData.messages.length; - const newMessage = modifiedData.messages[length - 1]; - const sid = newMessage.senderid; - const senderUsername = newMessage?.senderUsername; - if ( - sid !== currentUser.uid && - chat[1]?.userInfo?.uid !== sid - ) { - if (notificationGranted) { - const audio = new Audio( - '/assets/sounds/notification.mp3' - ); - const notification = new Notification('Dev Chat+', { - body: - 'New message from ' + - (senderUsername ? senderUsername : sid), - icon: '/logo192.png', - tag: sid, - }); - audio.play(); - notification.onclick = () => { - window.focus(); - }; - } else { - dispatch( - notifyAction( - true, - 'info', - 'New message from ' + - (senderUsername ? senderUsername : sid) - ) - ); - } - setSenderid(sid); - } - } - }); - }); + useEffect(() => { + const unsub2 = onSnapshot(collection(db, 'chats'), (snapshot) => { + snapshot.docChanges().forEach((change) => { + if (change.type === 'modified') { + const modifiedData = change.doc.data(); + const length = modifiedData.messages.length; + const newMessage = modifiedData.messages[length - 1]; + const sid = newMessage.senderid; + const senderUsername = newMessage?.senderUsername; + if ( + sid !== currentUser.uid && + chat[1]?.userInfo?.uid !== sid + ) { + if (notificationGranted) { + const audio = new Audio( + '/assets/sounds/notification.mp3' + ); + const notification = new Notification('Dev Chat+', { + body: + 'New message from ' + + (senderUsername ? senderUsername : sid), + icon: '/logo192.png', + tag: sid, + }); + audio.play(); + notification.onclick = () => { + window.focus(); + }; + } else { + dispatch( + notifyAction( + true, + 'info', + 'New message from ' + + (senderUsername ? senderUsername : sid) + ) + ); + } + setSenderid(sid); + } + } + }); + }); - return () => { - unsub2(); - }; - }, [chat, notificationGranted]); + return () => { + unsub2(); + }; + }, [chat, notificationGranted]); - return ( - - {/* The header with the name of the person. */} - - {/* The profile icon and name */} - setModalOpen(true)} - > - - - {currentUser.username} - - + variant='permanent' + anchor='left' + > + {/* The header with the name of the person. */} + + {/* The profile icon and name */} + setModalOpen(true)} + > + + + {currentUser.username} + + - {modalOpen && ( - - )} + {modalOpen && ( + + )} - {/* The menu icon */} - - + {/* The menu icon */} + + - {/* Not the header */} - - - - - ) + {/* Not the header */} + + + + + ); } diff --git a/client/src/components/home/HomeMenu.js b/client/src/components/home/HomeMenu.js index 7258f0c..f17ce3b 100644 --- a/client/src/components/home/HomeMenu.js +++ b/client/src/components/home/HomeMenu.js @@ -25,129 +25,161 @@ import LightModeIcon from '@mui/icons-material/LightMode'; import DarkModeIcon from '@mui/icons-material/DarkMode'; export default function HomeMenu({ - notificationGranted, setNotificationGranted, themeChange, mode + notificationGranted, + setNotificationGranted, + themeChange, + mode, + promptInstall, + supportsPWA, }) { - const dispatch = useDispatch(); + const dispatch = useDispatch(); - const [anchorEl, setAnchorEl] = useState(null); + const [anchorEl, setAnchorEl] = useState(null); - const logOut = () => { - const choice = window.confirm('Please click on OK to Log Out.'); - if (choice) { - signOut(auth) - .then(() => { - dispatch(signOutAction()); - }) - .catch((error) => { - // eslint-disable-next-line no-console - console.log(error); - dispatch( - notifyAction( - true, - 'error', - 'Log Out action Failed. Please try again' - ) - ); - }); - } - }; + const logOut = () => { + const choice = window.confirm('Please click on OK to Log Out.'); + if (choice) { + signOut(auth) + .then(() => { + dispatch(signOutAction()); + }) + .catch((error) => { + // eslint-disable-next-line no-console + console.log(error); + dispatch( + notifyAction( + true, + 'error', + 'Log Out action Failed. Please try again' + ) + ); + }); + } + }; - const handleInstall = () => { - dispatch(notifyAction(true, 'info', 'Install feature coming soon...')); - }; + const handleInstall = () => { + // dispatch(notifyAction(true, 'info', 'Install feature coming soon...')) + if (!supportsPWA) { + alert( + 'Either you have already installed the app or your browser does not support PWA :(' + ); + return; + } + promptInstall.prompt(); + }; - const notificationPrompt = () => { - Notification.requestPermission().then((result) => { - if (result === 'granted') { - setNotificationGranted(true); - const notification = new Notification('Dev Chat+', { - body: 'You will be notified like this when you receive a new message', - icon: '/assets/icons/maskable_icon_x48.png', + const notificationPrompt = () => { + Notification.requestPermission().then((result) => { + if (result === 'granted') { + setNotificationGranted(true); + const notification = new Notification('Dev Chat+', { + body: 'You will be notified like this when you receive a new message', + icon: '/assets/icons/maskable_icon_x48.png', + }); + const audio = new Audio('/assets/sounds/notification.mp3'); + audio.play(); + notification.onclick = () => { + window.focus(); + audio.pause(); + }; + } }); - const audio = new Audio('/assets/sounds/notification.mp3'); - audio.play(); - notification.onclick = () => { - window.focus(); - audio.pause(); - }; - } - }); - }; - - const handleMenuClick = (event) => { - setAnchorEl(event.currentTarget); - }; + }; - const handleMenuClose = () => { - setAnchorEl(null); - }; + const handleMenuClick = (event) => { + setAnchorEl(event.currentTarget); + }; + const handleMenuClose = () => { + setAnchorEl(null); + }; - return ( - - - - - - - - - - - - - - {mode === 'dark' ? ( - - ) : ( - - )} - - - - - - + + + + + + + + + + + + + {mode === 'dark' ? ( + + ) : ( + + )} + + + + + + + + + + + - - - - - - - - - - - - ) + + + + + + + ); } diff --git a/client/src/components/home/HomeRightSide.js b/client/src/components/home/HomeRightSide.js index 52601c5..9ed6672 100644 --- a/client/src/components/home/HomeRightSide.js +++ b/client/src/components/home/HomeRightSide.js @@ -132,7 +132,7 @@ export default function HomeRightSide({ mode, chat }) { return t.toString().substring(4, 15); }; - const INVITE_TEMPLATE = `Hey, I'm using Dev Chat+ for Video Calling + const INVITE_TEMPLATE = `Hey, I'm using Dev Chat+ for Productive Collaboration and much more. Join me on this room: ${process.env.REACT_APP_BASE_URL}/meet/${chat[0]}`; @@ -142,6 +142,7 @@ export default function HomeRightSide({ mode, chat }) { }; const startWorkspace = () => { + // handleSendMessage(INVITE_TEMPLATE, true); window.location.href = `/workspace/${chat[0]}`; }; @@ -174,11 +175,11 @@ export default function HomeRightSide({ mode, chat }) { pl: 2, ...(mode === 'dark' ? { - backgroundColor: 'info.dark', - } + backgroundColor: 'info.dark', + } : { - backgroundColor: 'primary.main', - }), + backgroundColor: 'primary.main', + }), position: 'sticky', top: 0, }} diff --git a/client/src/components/workspace/SideStrip.js b/client/src/components/workspace/SideStrip.js index 1c9626b..46077aa 100644 --- a/client/src/components/workspace/SideStrip.js +++ b/client/src/components/workspace/SideStrip.js @@ -27,7 +27,11 @@ import { doc, updateDoc, setDoc } from 'firebase/firestore'; import { db } from '../../firebaseConfig'; import { useParams } from 'react-router-dom'; import { useDispatch } from 'react-redux'; -import { notifyAction, startLoadingAction, stopLoadingAction } from '../../actions/actions'; +import { + notifyAction, + startLoadingAction, + stopLoadingAction, +} from '../../actions/actions'; const StyledToggleButtonGroup = styled(ToggleButtonGroup)(() => ({ '& .MuiToggleButtonGroup-grouped': { @@ -81,9 +85,7 @@ export default function SideStrip({ handleSelect, selected }) { const uploadDataToCloud = async () => { try { dispatch(startLoadingAction()); - dispatch( - notifyAction(true, 'success', 'Uploading data to cloud') - ); + dispatch(notifyAction(true, 'success', 'Uploading data to cloud')); const canvasData = localStorage.getItem( `${params.workspaceId}-drawing` ); @@ -93,7 +95,6 @@ export default function SideStrip({ handleSelect, selected }) { canvasData, }; const dbRef = doc(db, 'workspace', params.workspaceId); - await setDoc(dbRef,{code:'',canvasData:''}); await updateDoc(dbRef, data); window.location.href = '/chat'; } catch (error) { @@ -259,7 +260,19 @@ export default function SideStrip({ handleSelect, selected }) { )} - + { + navigator.clipboard.writeText(window.location.href); + dispatch( + notifyAction( + true, + 'success', + 'Workspace link copied to clipboard' + ) + ); + }} + > diff --git a/client/src/components/workspace/WorkSpace.js b/client/src/components/workspace/WorkSpace.js index 6bd3a71..423f64d 100644 --- a/client/src/components/workspace/WorkSpace.js +++ b/client/src/components/workspace/WorkSpace.js @@ -100,7 +100,6 @@ export default function WorkSpace() { canvasData, }; const dbRef = doc(db, 'workspace', params.workspaceId); - await setDoc(dbRef,{code:'',canvasData:''}); await updateDoc(dbRef, data); } catch (error) { dispatch( From c8a3bf9a53233b221766dd6a0e27df2acc087cc1 Mon Sep 17 00:00:00 2001 From: vishal-codes Date: Tue, 2 May 2023 00:18:57 +0530 Subject: [PATCH 2/2] fix: send meet & workspace link Signed-off-by: vishal-codes --- client/src/components/home/HomeRightSide.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/home/HomeRightSide.js b/client/src/components/home/HomeRightSide.js index 9ed6672..e11fd63 100644 --- a/client/src/components/home/HomeRightSide.js +++ b/client/src/components/home/HomeRightSide.js @@ -137,12 +137,12 @@ export default function HomeRightSide({ mode, chat }) { ${process.env.REACT_APP_BASE_URL}/meet/${chat[0]}`; const startVideoCall = () => { - // handleSendMessage(INVITE_TEMPLATE, true); + handleSendMessage(INVITE_TEMPLATE, true); window.location.href = `/meet/${chat[0]}`; }; const startWorkspace = () => { - // handleSendMessage(INVITE_TEMPLATE, true); + handleSendMessage(INVITE_TEMPLATE, true); window.location.href = `/workspace/${chat[0]}`; };