├── .gitignore ├── README.md ├── package.json ├── public ├── favicon.ico ├── firebase-messaging-sw.js ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── App.css ├── App.test.tsx ├── IsMobileViewContext.ts ├── assets │ ├── Image-518@1x.png │ ├── add-members.svg │ ├── audio-bubble.svg │ ├── avatar.png │ ├── badge.png │ ├── ban-members.svg │ ├── captainamerica_avatar.png │ ├── cometchat_logo.png │ ├── composer.png │ ├── contacts.svg │ ├── conversation.png │ ├── create-group.svg │ ├── cyclops_avatar.png │ ├── details.svg │ ├── file-bubble.svg │ ├── group-member.svg │ ├── image-bubble.svg │ ├── info.svg │ ├── ironman_avatar.png │ ├── list.png │ ├── listwrapper.png │ ├── loading_icon.gif │ ├── localize.png │ ├── new.svg │ ├── password-group.svg │ ├── power-off.png │ ├── receipt.png │ ├── right-arrow.png │ ├── sample.mp3 │ ├── sidebar.png │ ├── sound-small.png │ ├── spiderman_avatar.png │ ├── status.png │ ├── switch-mode.png │ ├── text-bubble.svg │ ├── theme.png │ ├── transfer-ownership-icon.svg │ ├── video-bubble.svg │ └── wolverine_avatar.png ├── components │ ├── App │ │ ├── App.tsx │ │ └── style.ts │ ├── Button │ │ ├── effects.ts │ │ └── index.tsx │ ├── ConversationsWithMessages.tsx │ ├── Login │ │ ├── index.tsx │ │ └── style.ts │ ├── LoginSignup │ │ ├── index.tsx │ │ └── style.ts │ ├── Signup │ │ ├── index.tsx │ │ └── style.ts │ └── TextInput │ │ ├── index.tsx │ │ └── style.ts ├── const.ts ├── custom-hooks.ts ├── firebase.js ├── index.css ├── index.tsx ├── logo.svg ├── react-app-env.d.ts ├── reportWebVitals.ts ├── sampleApp │ └── sampledata.js ├── setupTests.ts └── subject.js └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | CometChat 3 |

4 | 5 | # React Enhanced Push notifications (Beta) Sample app 6 | 7 | The CometChat React [Enhanced Push notifications (Beta)](https://www.cometchat.com/docs-beta/notifications/push-overview) Sample app is a fully functional push notification app capable of one-on-one (private) and group messaging, and Calling. This sample app enables users to send and receive push notifications for text and multimedia messages like **images, videos, documents** and **Custom Messages**. 8 | 9 | > [!NOTE] 10 | > If you are using Push Notifications (Extension), please refer to our [React Push Notifications (Extension)](https://github.com/cometchat/cometchat-push-notification-app-react/tree/v4-push-notifications-extension) Sample app for guidance. 11 | 12 | ## Pre-requisite 13 | 14 | 1. Login to the [CometChat Dashboard](https://app.cometchat.com/). 15 | 2. Select an existing app or create a new one. 16 | 3. Click on the Notifications section from the menu on the left. 17 | 4. Enable Push Notifications by clicking on the toggle bar and configure the push notifications. 18 | 5. Add credentials for FCM and make a note of the provider id. 19 | 20 | ## Run the Sample App 21 | 22 | 1. Clone this repository. 23 | 2. Install the dependencies: 24 | 25 | ``` 26 | npm i 27 | ``` 28 | 29 | 3. Paste the `firebaseConfig` in the correct location as per FCM's documentation. 30 | 4. Add your app credentials like `appId`, `region`, `authKey` in the `src/const.ts`. 31 | 5. Also add the `fcmProviderId` in `src/const.ts` as that is required while registering push token. 32 | 6. Add `vapidKey` obtained from the Firebase console -> Cloud Messaging -> Web Push Certificates to the `firebase.js`. 33 | 7. Run the sample app. 34 | ``` 35 | npm start 36 | ``` 37 | 38 | 8. Once the app opens up in a browser, login with a user. 39 | 9. Allow the permission to display push notifications. 40 | 10. Send a message or call to the logged in user from another browser/device. 41 | 11. You should see a push notification for a message. 42 | 12. Tap on the notification to open the Sample app for message. 43 | 44 | ## Help and Support 45 | 46 | For issues running the project or integrating with our UI Kits, consult our [documentation](https://www.cometchat.com/docs-beta/notifications/push-overview) or create a [support ticket](https://help.cometchat.com/hc/en-us) or seek real-time support via the [CometChat Dashboard](https://app.cometchat.com/). 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "v4-react-push", 3 | "version": "0.1.1", 4 | "private": true, 5 | "dependencies": { 6 | "@cometchat/calls-sdk-javascript": "^4.0.9", 7 | "@cometchat/chat-sdk-javascript": "^4.0.6", 8 | "@cometchat/chat-uikit-react": "^4.3.8", 9 | "@cometchat/uikit-elements": "^4.3.9", 10 | "@cometchat/uikit-resources": "^4.3.8", 11 | "@cometchat/uikit-shared": "^4.3.10", 12 | "@testing-library/jest-dom": "^5.17.0", 13 | "@testing-library/react": "^13.4.0", 14 | "@testing-library/user-event": "^13.5.0", 15 | "@types/jest": "^27.5.2", 16 | "@types/node": "^16.18.48", 17 | "@types/react": "^18.2.21", 18 | "@types/react-dom": "^18.2.7", 19 | "@types/react-router-dom": "^5.3.3", 20 | "firebase": "^10.3.1", 21 | "react": "^18.2.0", 22 | "react-dom": "^18.2.0", 23 | "react-hot-toast": "^2.4.1", 24 | "react-router-dom": "^6.16.0", 25 | "react-scripts": "5.0.1", 26 | "typescript": "^4.9.5", 27 | "web-vitals": "^2.1.4" 28 | }, 29 | "scripts": { 30 | "start": "react-scripts start", 31 | "build": "react-scripts build", 32 | "test": "react-scripts test", 33 | "eject": "react-scripts eject" 34 | }, 35 | "eslintConfig": { 36 | "extends": [ 37 | "react-app", 38 | "react-app/jest" 39 | ] 40 | }, 41 | "browserslist": { 42 | "production": [ 43 | ">0.2%", 44 | "not dead", 45 | "not op_mini all" 46 | ], 47 | "development": [ 48 | "last 1 chrome version", 49 | "last 1 firefox version", 50 | "last 1 safari version" 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/public/favicon.ico -------------------------------------------------------------------------------- /public/firebase-messaging-sw.js: -------------------------------------------------------------------------------- 1 | // /* eslint-disable no-restricted-globals */ 2 | // /* eslint-disable no-undef */ 3 | // // required to setup background notification handler when browser is not in focus or in background and 4 | // // In order to receive the onMessage event, app must define the Firebase messaging service worker 5 | // // self.importScripts("localforage.js"); 6 | 7 | importScripts( 8 | "https://www.gstatic.com/firebasejs/9.15.0/firebase-app-compat.js" 9 | ); 10 | importScripts( 11 | "https://www.gstatic.com/firebasejs/9.15.0/firebase-messaging-compat.js" 12 | ); 13 | var TAG = "[Firebase-sw.js]"; 14 | 15 | self.addEventListener("notificationclick", async function (event) { 16 | console.log(TAG, "notificationclick", event, event.clientId); 17 | if (event?.notification?.data) { 18 | let data = event.notification.data; 19 | event.waitUntil( 20 | self.clients 21 | .matchAll({ type: "window", includeUncontrolled: true }) 22 | .then((clientList) => { 23 | if (clientList.length > 0) { 24 | clientList[0].postMessage({ 25 | message: data, 26 | }); 27 | return ( 28 | clientList[0] 29 | .focus() 30 | .catch((error) => { 31 | console.log(error); 32 | return self.clients.openWindow(clientList[0].url); // Adjust this URL as necessary for your application 33 | }) 34 | ); 35 | } else { 36 | // Open a new client (tab) if there are no existing clients 37 | self.clients.openWindow("/"); 38 | setTimeout(() => { 39 | self.clients 40 | .matchAll({ type: "window", includeUncontrolled: true }) 41 | .then((clientList) => { 42 | if (clientList.length > 0) { 43 | clientList[0].postMessage({ 44 | message: {...data,fromBackground: true}, 45 | }); 46 | } 47 | return; 48 | }); 49 | }, 1500); 50 | } 51 | }) 52 | ); 53 | } 54 | 55 | event.notification.close(); 56 | }); 57 | // "Default" Firebase configuration (prevents errors) 58 | const defaultConfig = { 59 | apiKey: true, 60 | projectId: true, 61 | messagingSenderId: true, 62 | appId: true, 63 | }; 64 | 65 | // Initialize Firebase app 66 | firebase.initializeApp(self.firebaseConfig || defaultConfig); 67 | let messaging; 68 | try { 69 | messaging = firebase.messaging(); 70 | // Customize background notification handling here 71 | messaging.onBackgroundMessage((payload) => { 72 | console.log("Background Message:", payload); 73 | const notificationTitle = payload.data.title; 74 | if ( 75 | payload.data.type === "call" && 76 | (payload.data.callAction === "unanswered" || 77 | payload.data.callAction === "busy" || 78 | payload.data.callAction === "ongoing") 79 | ) { 80 | return; 81 | } 82 | let body = payload.data.body; 83 | if (payload.data.type === "call") { 84 | switch (payload.data.callAction) { 85 | case "cancelled": 86 | body = `Call cancelled`; 87 | break; 88 | case "initiated": 89 | body = `Incoming ${payload.data.callType} call`; 90 | break; 91 | default: 92 | break; 93 | } 94 | } 95 | const notificationOptions = { 96 | title: payload.data.title, 97 | icon: payload.data.senderAvatar, 98 | data: payload.data, 99 | tag: payload.data.tag, 100 | body: body, 101 | }; 102 | self.registration.showNotification(notificationTitle, notificationOptions); 103 | }); 104 | } catch (err) { 105 | console.error("Failed to initialize Firebase Messaging", err); 106 | } 107 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/App.css -------------------------------------------------------------------------------- /src/App.test.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { render, screen } from "@testing-library/react"; 3 | import App from "./components/App/App"; 4 | 5 | test("renders learn react link", () => { 6 | render(); 7 | const linkElement = screen.getByText(/learn react/i); 8 | expect(linkElement).toBeInTheDocument(); 9 | }); 10 | -------------------------------------------------------------------------------- /src/IsMobileViewContext.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const IsMobileViewContext = createContext(false); 4 | -------------------------------------------------------------------------------- /src/assets/Image-518@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/Image-518@1x.png -------------------------------------------------------------------------------- /src/assets/add-members.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/audio-bubble.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/avatar.png -------------------------------------------------------------------------------- /src/assets/badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/badge.png -------------------------------------------------------------------------------- /src/assets/ban-members.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/captainamerica_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/captainamerica_avatar.png -------------------------------------------------------------------------------- /src/assets/cometchat_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/cometchat_logo.png -------------------------------------------------------------------------------- /src/assets/composer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/composer.png -------------------------------------------------------------------------------- /src/assets/contacts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Icons/24/Contacts 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/conversation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/conversation.png -------------------------------------------------------------------------------- /src/assets/create-group.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | group_add 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/cyclops_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/cyclops_avatar.png -------------------------------------------------------------------------------- /src/assets/details.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/assets/file-bubble.svg: -------------------------------------------------------------------------------- 1 | folder, file, archive, document, office -------------------------------------------------------------------------------- /src/assets/group-member.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 13 | 16 | 20 | 24 | 34 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /src/assets/image-bubble.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | Icons/24/Info 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/assets/ironman_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/ironman_avatar.png -------------------------------------------------------------------------------- /src/assets/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/list.png -------------------------------------------------------------------------------- /src/assets/listwrapper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/listwrapper.png -------------------------------------------------------------------------------- /src/assets/loading_icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/loading_icon.gif -------------------------------------------------------------------------------- /src/assets/localize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/localize.png -------------------------------------------------------------------------------- /src/assets/new.svg: -------------------------------------------------------------------------------- 1 | Icons/24/New -------------------------------------------------------------------------------- /src/assets/password-group.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/power-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/power-off.png -------------------------------------------------------------------------------- /src/assets/receipt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/receipt.png -------------------------------------------------------------------------------- /src/assets/right-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/right-arrow.png -------------------------------------------------------------------------------- /src/assets/sample.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/sample.mp3 -------------------------------------------------------------------------------- /src/assets/sidebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/sidebar.png -------------------------------------------------------------------------------- /src/assets/sound-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/sound-small.png -------------------------------------------------------------------------------- /src/assets/spiderman_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/spiderman_avatar.png -------------------------------------------------------------------------------- /src/assets/status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/status.png -------------------------------------------------------------------------------- /src/assets/switch-mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/switch-mode.png -------------------------------------------------------------------------------- /src/assets/text-bubble.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/assets/theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/theme.png -------------------------------------------------------------------------------- /src/assets/transfer-ownership-icon.svg: -------------------------------------------------------------------------------- 1 | a -------------------------------------------------------------------------------- /src/assets/video-bubble.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/assets/wolverine_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cometchat/cometchat-push-notification-app-react/769451dad40e9d6f25fc7f7c27a82f2144eb8006/src/assets/wolverine_avatar.png -------------------------------------------------------------------------------- /src/components/App/App.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unused-vars */ 2 | import { Navigate, Route, Routes, useNavigate } from "react-router-dom"; 3 | 4 | import { CometChatTheme } from "@cometchat/chat-uikit-react"; 5 | import { useEffect, useLayoutEffect, useState } from "react"; 6 | import { CometChat } from "@cometchat/chat-sdk-javascript"; 7 | import { Login } from "../Login"; 8 | import { IsMobileViewContext } from "../../IsMobileViewContext"; 9 | import { appStyle } from "./style"; 10 | 11 | import firebaseInitialize from "../../firebase"; 12 | import ConversationsWithMessages from "../ConversationsWithMessages"; 13 | function App() { 14 | const navigate = useNavigate(); 15 | const [isMobileView, setIsMobileView] = useState(false); 16 | const [theme, setTheme] = useState(new CometChatTheme({})); 17 | 18 | 19 | useEffect(() => { 20 | // Assuming the service worker has already been registered elsewhere 21 | if (navigator.serviceWorker) { 22 | // Listen for messages from the service worker 23 | const handleServiceWorkerMessage = (event: any) => { 24 | console.log( 25 | "Received a message from service worker:", 26 | event, 27 | event.data.message 28 | ); 29 | // Handle the message or payload here 30 | // You can pass the message to your component's state or context 31 | if (navigate) { 32 | navigate("/conversationsWithMessages", { state: event.data.message }); 33 | return; 34 | } 35 | }; 36 | 37 | navigator.serviceWorker.addEventListener( 38 | "message", 39 | handleServiceWorkerMessage 40 | ); 41 | 42 | // Cleanup listener when the component unmounts 43 | return () => { 44 | navigator.serviceWorker.removeEventListener( 45 | "message", 46 | handleServiceWorkerMessage 47 | ); 48 | }; 49 | } 50 | }, []); 51 | 52 | useLayoutEffect(() => { 53 | firebaseInitialize(navigate); 54 | },[]) 55 | 56 | useEffect(() => { 57 | function handleResize() { 58 | if (window.innerWidth <= 768) setIsMobileView(true); 59 | else setIsMobileView(false); 60 | } 61 | window.addEventListener("resize", handleResize); 62 | }, [setIsMobileView]); 63 | 64 | return ( 65 |
66 |
72 |
83 | 84 | 85 | 86 | }> 87 | } 90 | /> 91 | 92 | } /> 93 | 94 | 95 | 96 |
97 |
98 |
99 | ); 100 | } 101 | 102 | const CheckLogin = () => { 103 | const [loggedInUser, setLoggedInUser] = useState< 104 | CometChat.User | null | undefined 105 | >(null); 106 | const [interestingAsyncOpStarted, setInterestingAsyncOpStarted] = useState( 107 | false 108 | ); 109 | const navigate = useNavigate(); 110 | useLayoutEffect(() => { 111 | (async () => { 112 | try { 113 | setLoggedInUser(await CometChat.getLoggedinUser()); 114 | } catch (error) { 115 | console.log(error); 116 | } 117 | })(); 118 | }, []); 119 | 120 | useEffect(() => { 121 | if (loggedInUser) { 122 | navigate("/conversationsWithMessages"); 123 | } 124 | }, [loggedInUser]) 125 | 126 | return ( 127 | 132 | ); 133 | }; 134 | 135 | export default App; 136 | -------------------------------------------------------------------------------- /src/components/App/style.ts: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react"; 2 | import { CometChatTheme } from "@cometchat/uikit-resources"; 3 | 4 | const LOGGED_IN_USER_INFO_CONTAINER_HEIGHT = "48px"; 5 | const FOOTER_HEIGHT = "48px"; 6 | 7 | export function appStyle(theme: CometChatTheme): CSSProperties { 8 | return { 9 | height: "100%", 10 | boxSizing: "border-box", 11 | backgroundColor: theme.palette.getBackground(), 12 | position: "relative", 13 | overflowX: "hidden", 14 | }; 15 | } 16 | 17 | export function footerStyle(): CSSProperties { 18 | return { 19 | display: "flex", 20 | justifyContent: "center", 21 | alignItems: "center", 22 | height: FOOTER_HEIGHT, 23 | }; 24 | } 25 | 26 | export function messageStyle(isError: boolean): CSSProperties { 27 | return { 28 | padding: "16px", 29 | color: "white", 30 | textAlign: "center", 31 | backgroundColor: isError ? "red" : "green", 32 | borderRadius: "8px", 33 | width: "300px", 34 | boxSizing: "border-box", 35 | position: "fixed", 36 | top: "32px", 37 | left: "50%", 38 | transform: "translateX(-50%)", 39 | }; 40 | } 41 | 42 | export function loggedInUserInfoContainerStyle(): CSSProperties { 43 | return { 44 | height: LOGGED_IN_USER_INFO_CONTAINER_HEIGHT, 45 | display: "flex", 46 | justifyContent: "flex-end", 47 | alignItems: "center", 48 | columnGap: "8px", 49 | padding: "0 16px", 50 | }; 51 | } 52 | 53 | export function uidStyle(): CSSProperties { 54 | return { 55 | fontWeight: "600", 56 | }; 57 | } 58 | 59 | export function logoutBtnStyle(): CSSProperties { 60 | return { 61 | cursor: "pointer", 62 | backgroundColor: "transparent", 63 | border: "none", 64 | }; 65 | } 66 | 67 | export function logoutImgStyle(): CSSProperties { 68 | return { 69 | width: "24px", 70 | height: "24px", 71 | }; 72 | } 73 | 74 | export function loadingModalStyle(showModal: boolean): CSSProperties { 75 | return { 76 | display: showModal ? "flex" : "none", 77 | width: "100vw", 78 | height: "100vh", 79 | backgroundColor: "#393b39", 80 | position: "fixed", 81 | top: "0", 82 | left: "0", 83 | justifyContent: "center", 84 | alignItems: "center", 85 | }; 86 | } 87 | 88 | export function imageStyle(): CSSProperties { 89 | return { 90 | backgroundSize: "cover", 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /src/components/Button/effects.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | interface IEffectsProps { 4 | ref : React.MutableRefObject, 5 | onClickPropRef : React.MutableRefObject<((customEvent: CustomEvent<{event: PointerEvent}>) => void) | undefined> 6 | }; 7 | 8 | export function Effects(props : IEffectsProps) { 9 | const { 10 | ref, 11 | onClickPropRef 12 | } = props; 13 | 14 | useEffect(() => { 15 | const buttonElement = ref.current; 16 | const eventName = "cc-button-clicked"; 17 | const handleEvent = (e : CustomEvent<{event : PointerEvent}>) => onClickPropRef.current?.(e); 18 | buttonElement.addEventListener(eventName, handleEvent); 19 | return () => { 20 | buttonElement.removeEventListener(eventName, handleEvent); 21 | }; 22 | }, [onClickPropRef, ref]); // Refs are in the dependency array to satisfy ESlint 23 | } 24 | -------------------------------------------------------------------------------- /src/components/Button/index.tsx: -------------------------------------------------------------------------------- 1 | import { CSSProperties, useRef } from "react"; 2 | import { useRefSync } from "../../custom-hooks"; 3 | import { Effects } from "./effects"; 4 | 5 | export type ButtonStyle = { 6 | buttonTextFont?: string; 7 | buttonTextColor?: string; 8 | buttonIconTint?: string; 9 | } & CSSProperties; 10 | 11 | interface IButtonProps { 12 | text?: string; 13 | hoverText?: string; 14 | iconURL?: string; 15 | disabled?: boolean; 16 | buttonStyle?: ButtonStyle; 17 | onClick?: (customEvent: CustomEvent<{ event: PointerEvent }>) => void; 18 | } 19 | 20 | export function Button(props: IButtonProps) { 21 | const { text, hoverText, iconURL, disabled, buttonStyle, onClick } = props; 22 | 23 | const ref = useRef(); 24 | const onClickPropRef = useRefSync(onClick); 25 | 26 | function getDisabledPropSpreadObject(): { disabled?: true } { 27 | return disabled ? { disabled } : {}; 28 | } 29 | 30 | function getStylePropSpreadObject( 31 | styleObject: T1, 32 | stylePropName: T2 33 | ): { T2?: string } { 34 | return styleObject ? { [stylePropName]: JSON.stringify(styleObject) } : {}; 35 | } 36 | 37 | Effects({ 38 | ref, 39 | onClickPropRef, 40 | }); 41 | 42 | return ( 43 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /src/components/ConversationsWithMessages.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { CometChat, CometChatNotifications } from "@cometchat/chat-sdk-javascript"; 3 | import { 4 | CometChatContacts, 5 | CometChatConversationsWithMessages, 6 | CometChatIncomingCall, 7 | CometChatTheme, 8 | CometChatUIKit, 9 | CometChatUIKitConstants, 10 | ConversationsConfiguration, 11 | } from "@cometchat/chat-uikit-react"; 12 | import { useLocation, useNavigate } from "react-router-dom"; 13 | import { Button } from "./Button"; 14 | import PowerOff from "../assets/power-off.png"; 15 | import newIcon from "../assets/new.svg"; 16 | 17 | const incomingcallListenerId = "incomingcall_listener_id"; 18 | 19 | function ConversationsWithMessages() { 20 | const [user, setUser] = useState(); 21 | const [call, setCall] = useState(); 22 | const [theme, setTheme] = useState(new CometChatTheme({})); 23 | const [group, setGroup] = useState(); 24 | const [contacts, setContacts] = useState(false); 25 | 26 | const navigate = useNavigate(); 27 | 28 | const { state } = useLocation(); 29 | 30 | const logout = () => { 31 | CometChatNotifications.unregisterPushToken().then((res)=>{ 32 | console.log(res); 33 | }) 34 | CometChatUIKit.logout()!.then( 35 | () => { 36 | console.log("Logout completed successfully"); 37 | navigate("/"); 38 | }, 39 | (error: any) => { 40 | console.log("Logout failed with exception:", { error }); 41 | } 42 | ); 43 | }; 44 | 45 | useEffect(() => { 46 | CometChat.addCallListener( 47 | incomingcallListenerId, 48 | new CometChat.CallListener({ 49 | onIncomingCallCancelled: (call: CometChat.Call) => { 50 | console.log("onIncomingCallCancelled", call); 51 | setCall(undefined); 52 | CometChat.removeCallListener(incomingcallListenerId); 53 | }, 54 | onOutgoingCallRejected: (call: CometChat.Call) => { 55 | console.log("onOutgoingCallRejected", call); 56 | setCall(undefined); 57 | CometChat.removeCallListener(incomingcallListenerId); 58 | }, 59 | }) 60 | ); 61 | return () => { 62 | CometChat.removeCallListener(incomingcallListenerId); 63 | }; 64 | }, []); 65 | 66 | useEffect(() => { 67 | if (state && state.receiverType === "user" && state.sender) { 68 | CometChat.getUser(state.sender).then(async (user) => { 69 | setGroup(null); 70 | setUser(user); 71 | if (state.fromBackground && state.type === "call") { 72 | let newCall = new CometChat.Call( 73 | state.receiver, 74 | state.callType, 75 | state.receiverType 76 | ); 77 | newCall.setSessionId(state.sessionId); 78 | newCall.setCallInitiator(new CometChat.User(user)); 79 | newCall.setSender(user); 80 | setCall(newCall); 81 | } 82 | }); 83 | } else if (state && state.receiverType === "group") { 84 | CometChat.getGroup(state.receiver).then((group) => { 85 | setUser(null); 86 | setGroup(group); 87 | }); 88 | } 89 | }, [state]); 90 | 91 | return ( 92 | <> 93 | {call ? ( 94 | <> 95 | { 98 | CometChat.rejectCall( 99 | call.sessionId, 100 | CometChatUIKitConstants.calls.rejected 101 | ) 102 | .then((rejectedCall: CometChat.Call) => { 103 | console.log("rejectedCall", rejectedCall); 104 | }) 105 | .finally(() => { 106 | setCall(undefined); 107 | }); 108 | CometChat.removeCallListener(incomingcallListenerId); 109 | }} 110 | onError={() => { 111 | console.log("onError"); 112 | setCall(undefined); 113 | CometChat.removeCallListener(incomingcallListenerId); 114 | }} 115 | /> 116 | 117 | ) : ( 118 | 119 | )} 120 | {contacts ? ( 121 | { 123 | setUser(user); 124 | setGroup(group); 125 | setContacts(false); 126 | }} 127 | /> 128 | ): 129 | 139 | 140 | 107 | ); 108 | } 109 | 110 | useEffect(()=>{ 111 | fetchDefaultUsers(); 112 | return () =>{ 113 | setDefaultUsers([]); 114 | } 115 | },[]) 116 | 117 | function getErrorMessage() { 118 | if (!errorMessage) { 119 | return null; 120 | } 121 | return
{errorMessage}
; 122 | } 123 | 124 | if (loggedInUser === undefined) { 125 | return null; 126 | } 127 | 128 | if (loggedInUser) { 129 | return ; 130 | } 131 | return ( 132 | 133 |
134 |
135 |
136 | Using our sample users 137 |
138 |
139 | {defaultUsers.map(getUserBtnWithKeyAdded)} 140 |
141 |
142 |
146 | 153 | 154 | 155 | {getErrorMessage()} 156 |
157 |
Don't have an account?
158 | 164 |
165 |
166 |
167 | ); 168 | } 169 | -------------------------------------------------------------------------------- /src/components/Login/style.ts: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react"; 2 | import { CometChatTheme, fontHelper } from "@cometchat/uikit-resources"; 3 | 4 | export function loginStyle(): CSSProperties { 5 | return { 6 | display: "flex", 7 | flexDirection: "column", 8 | rowGap: "48px", 9 | }; 10 | } 11 | 12 | export function userBtnStyle(theme: CometChatTheme): CSSProperties { 13 | return { 14 | flexBasis: "48%", 15 | padding: "8px", 16 | backgroundColor: theme.palette.getAccent100("light"), 17 | borderRadius: "8px", 18 | display: "flex", 19 | alignItems: "center", 20 | columnGap: "8px", 21 | cursor: "pointer", 22 | border: `1px solid ${theme.palette.getAccent100("light")}`, 23 | }; 24 | } 25 | 26 | export function userAvatarStyle(): CSSProperties { 27 | return { 28 | width: "32px", 29 | height: "32px", 30 | backgroundColor: "white", 31 | borderRadius: "24px", 32 | }; 33 | } 34 | 35 | export function defaultUserBtnsContainerStyle(): CSSProperties { 36 | return { 37 | display: "grid", 38 | gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))", 39 | gap: "8px", 40 | }; 41 | } 42 | 43 | export function loginSampleUsersContainerStyle(): CSSProperties { 44 | return { 45 | display: "flex", 46 | flexDirection: "column", 47 | rowGap: "4px", 48 | }; 49 | } 50 | 51 | export function loginBtnStyle(theme: CometChatTheme): CSSProperties { 52 | return { 53 | backgroundColor: theme.palette.getPrimary(), 54 | font: fontHelper(theme.typography.subtitle1), 55 | color: theme.palette.getAccent900("light"), 56 | borderRadius: "8px", 57 | padding: "8px", 58 | border: `1px solid ${theme.palette.getAccent100("light")}`, 59 | width: "100%", 60 | cursor: "pointer", 61 | }; 62 | } 63 | 64 | export function loginUidFormStyle(): CSSProperties { 65 | return { 66 | display: "flex", 67 | flexDirection: "column", 68 | rowGap: "8px", 69 | }; 70 | } 71 | 72 | export function goToSignupContainerStyle(): CSSProperties { 73 | return { 74 | paddingTop: "16px", 75 | display: "flex", 76 | flexDirection: "column", 77 | rowGap: "16px", 78 | alignItems: "center", 79 | paddingBottom: "32px", 80 | textAlign: "center", 81 | }; 82 | } 83 | 84 | export function goToSignupStyle(theme: CometChatTheme): CSSProperties { 85 | return { 86 | font: fontHelper(theme.typography.title2), 87 | backgroundColor: "transparent", 88 | borderRadius: "4px", 89 | color: theme.palette.getAccent600("light"), 90 | textTransform: "capitalize", 91 | border: `1px solid ${theme.palette.getAccent100("light")}`, 92 | cursor: "pointer", 93 | }; 94 | } 95 | 96 | export function usingSampleUsersTextStyle( 97 | theme: CometChatTheme 98 | ): CSSProperties { 99 | return { 100 | font: fontHelper(theme.typography.subtitle2), 101 | color: theme.palette.getAccent600("light"), 102 | }; 103 | } 104 | 105 | export function noAccountStyle(theme: CometChatTheme): CSSProperties { 106 | return { 107 | font: fontHelper(theme.typography.subtitle1), 108 | color: theme.palette.getAccent600("light"), 109 | }; 110 | } 111 | 112 | export function userNameStyle(theme: CometChatTheme): CSSProperties { 113 | return { 114 | textTransform: "capitalize", 115 | font: fontHelper(theme.typography.name), 116 | color: theme.palette.getAccent("light"), 117 | textAlign: "left", 118 | }; 119 | } 120 | 121 | export function userUidStyle(theme: CometChatTheme): CSSProperties { 122 | return { 123 | font: fontHelper(theme.typography.subtitle2), 124 | color: theme.palette.getAccent600("light"), 125 | }; 126 | } 127 | 128 | export function userNameAndUidContainerStyle(): CSSProperties { 129 | return { 130 | display: "flex", 131 | flexDirection: "column", 132 | rowGap: "2px", 133 | alignItems: "flex-start", 134 | }; 135 | } 136 | 137 | export function errorMessageStyle(theme: CometChatTheme): CSSProperties { 138 | return { 139 | font: fontHelper(theme.typography.subtitle2), 140 | color: theme.palette.getError(), 141 | }; 142 | } 143 | -------------------------------------------------------------------------------- /src/components/LoginSignup/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | cardStyle, 3 | chatHeaderTextStyle, 4 | contentContainerStyle, 5 | contentStyle, 6 | footerStyle, 7 | headerStyle, 8 | headerTitle, 9 | imageStyle, 10 | loginSignupStyle, 11 | mainContainerStyle, 12 | titleStyle, 13 | versionStyle, 14 | } from "./style"; 15 | 16 | import { CometChatThemeContext } from "@cometchat/chat-uikit-react"; 17 | import Image from "../../assets/Image-518@1x.png"; 18 | import { useContext } from "react"; 19 | import { IsMobileViewContext } from "../../IsMobileViewContext"; 20 | 21 | interface ILoginSignupProps { 22 | title: string; 23 | children: JSX.Element; 24 | } 25 | 26 | export function LoginSignup(props: ILoginSignupProps) { 27 | const { title, children } = props; 28 | 29 | const { theme } = useContext(CometChatThemeContext); 30 | const isMobileView = useContext(IsMobileViewContext); 31 | 32 | function getHeader() { 33 | return ( 34 |
35 |
36 | comet 37 | chat 38 |
39 |
v4.0.0
40 |
41 | ); 42 | } 43 | 44 | function getContent() { 45 | return ( 46 |
47 |
48 |
{title}
49 |
{children}
50 |
51 | Login signup 52 |
53 | ); 54 | } 55 | 56 | function getFooter() { 57 | return
2023 ⓒ CometChat
; 58 | } 59 | 60 | return ( 61 |
62 |
63 | {getHeader()} 64 | {getContent()} 65 | {getFooter()} 66 |
67 |
68 | ); 69 | } 70 | -------------------------------------------------------------------------------- /src/components/LoginSignup/style.ts: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react"; 2 | import { CometChatTheme, fontHelper } from "@cometchat/uikit-resources"; 3 | 4 | export function loginSignupStyle() : CSSProperties { 5 | return { 6 | height: "100%", 7 | display: "flex", 8 | justifyContent: "center" 9 | }; 10 | } 11 | 12 | export function mainContainerStyle() : CSSProperties { 13 | return { 14 | width: "min(100%, 1400px)", 15 | height: "100%", 16 | display: "flex", 17 | flexDirection: "column", 18 | alignItems: "center", 19 | rowGap: "8px", 20 | boxSizing: "border-box", 21 | padding: "8px" 22 | }; 23 | } 24 | 25 | export function headerStyle(theme : CometChatTheme) : CSSProperties { 26 | return { 27 | width: "100%", 28 | padding: "16px", 29 | display: "flex", 30 | justifyContent: "space-between", 31 | borderBottom: `1px solid ${theme.palette.getAccent100()}` 32 | }; 33 | } 34 | 35 | export function contentContainerStyle() : CSSProperties { 36 | return { 37 | width: "100%", 38 | display: "flex", 39 | justifyContent: "center", 40 | alignItems: "center", 41 | columnGap: "8px" 42 | }; 43 | } 44 | 45 | export function footerStyle(theme : CometChatTheme) : CSSProperties { 46 | return { 47 | padding: "16px", 48 | flexGrow: "1", 49 | font: fontHelper(theme.typography.subtitle2), 50 | color: theme.palette.getAccent500(), 51 | display: "flex", 52 | alignItems: "flex-end" 53 | }; 54 | } 55 | 56 | export function chatHeaderTextStyle() : CSSProperties { 57 | return { 58 | fontWeight: "bold" 59 | }; 60 | } 61 | 62 | export function contentStyle(isMobileView : boolean) : CSSProperties { 63 | return { 64 | display: "flex", 65 | flexDirection: "column", 66 | rowGap: "8px", 67 | width: isMobileView ? "80%" : "50%" 68 | }; 69 | } 70 | 71 | export function titleStyle(theme : CometChatTheme) : CSSProperties { 72 | return { 73 | font: fontHelper(theme.typography.heading), 74 | color: theme.palette.getAccent() 75 | }; 76 | } 77 | 78 | export function cardStyle() : CSSProperties { 79 | return { 80 | backgroundColor: "white", 81 | borderRadius: "8px", 82 | boxShadow: "0 0 8px rgb(20, 20, 20, 0.33)", 83 | padding: "16px" 84 | }; 85 | } 86 | 87 | export function imageStyle(showImage : boolean) : CSSProperties { 88 | return { 89 | display: showImage ? "inline" : "none", 90 | width: "50%", 91 | backgroundSize: "contain" 92 | }; 93 | } 94 | 95 | export function headerTitle(theme : CometChatTheme) : CSSProperties { 96 | return { 97 | font: fontHelper(theme.typography.name) 98 | }; 99 | } 100 | 101 | export function versionStyle(theme : CometChatTheme) : CSSProperties { 102 | return { 103 | font: fontHelper(theme.typography.subtitle2), 104 | color: theme.palette.getAccent400() 105 | }; 106 | } 107 | -------------------------------------------------------------------------------- /src/components/Signup/index.tsx: -------------------------------------------------------------------------------- 1 | import { Navigate, useNavigate } from "react-router-dom"; 2 | import { 3 | checkboxTextStyle, 4 | errorMessageStyle, 5 | formStyle, 6 | generateUidCheckboxStyle, 7 | generateUidStyle, 8 | submitBtnStyle, 9 | } from "./style"; 10 | import { useContext, useState } from "react"; 11 | 12 | import { CometChat } from "@cometchat/chat-sdk-javascript"; 13 | import { CometChatConstants } from "../../const"; 14 | import { CometChatThemeContext } from "@cometchat/chat-uikit-react"; 15 | import { LoginSignup } from "../LoginSignup"; 16 | import { TextInput } from "../TextInput"; 17 | 18 | interface ISignUp { 19 | loggedInUser: CometChat.User | null | undefined; 20 | setLoggedInUser: React.Dispatch< 21 | React.SetStateAction 22 | >; 23 | setInterestingAsyncOpStarted: React.Dispatch>; 24 | } 25 | 26 | export function Signup({ 27 | loggedInUser, 28 | setLoggedInUser, 29 | setInterestingAsyncOpStarted, 30 | }: ISignUp) { 31 | const [name, setName] = useState(""); 32 | const [uid, setUid] = useState(""); 33 | const [generateUid, setGenerateUid] = useState(false); 34 | const [errorMessage, setErrorMessage] = useState(""); 35 | const navigate = useNavigate(); 36 | const { theme } = useContext(CometChatThemeContext); 37 | 38 | async function handleSubmit(e: React.FormEvent) { 39 | e.preventDefault(); 40 | console.log("Form submitted"); 41 | let newUserUid = uid; 42 | if (generateUid) { 43 | newUserUid = `${name.replaceAll(" ", "")}_${Date.now()}`; 44 | } 45 | const newUser = new CometChat.User(newUserUid); 46 | newUser.setName(name); 47 | try { 48 | setInterestingAsyncOpStarted(true); 49 | const createdUser = await CometChat.createUser( 50 | newUser, 51 | CometChatConstants.authKey 52 | ); 53 | console.log("User created:", createdUser); 54 | console.log( 55 | `User having uid: ${createdUser.getUid()} created successfully.` 56 | ); 57 | setLoggedInUser(createdUser); 58 | 59 | setName(""); 60 | setUid(""); 61 | setGenerateUid(false); 62 | navigate("/home"); 63 | } catch (error) { 64 | if (error instanceof CometChat.CometChatException && error.message) { 65 | setErrorMessage(error.message); 66 | } 67 | console.log(error); 68 | } finally { 69 | setInterestingAsyncOpStarted(false); 70 | } 71 | } 72 | 73 | if (loggedInUser === undefined) { 74 | return null; 75 | } 76 | 77 | if (loggedInUser) { 78 | return ; 79 | } 80 | 81 | return ( 82 | 83 |
84 | 90 | 97 |
98 | setGenerateUid(!generateUid)} 102 | style={generateUidCheckboxStyle()} 103 | /> 104 | 105 | By clicking on this checkbox, UID will be generated automatically. 106 | 107 |
108 |
{errorMessage}
109 | 112 | 113 |
114 | ); 115 | } 116 | -------------------------------------------------------------------------------- /src/components/Signup/style.ts: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react"; 2 | import { CometChatTheme, fontHelper } from "@cometchat/uikit-resources"; 3 | 4 | export function formStyle() : CSSProperties { 5 | return { 6 | display: "flex", 7 | flexDirection: "column", 8 | rowGap: "16px" 9 | }; 10 | } 11 | 12 | export function generateUidCheckboxStyle() : CSSProperties { 13 | return { 14 | width: "24px", 15 | height: "24px", 16 | cursor: "pointer" 17 | }; 18 | } 19 | 20 | export function generateUidStyle() : CSSProperties { 21 | return { 22 | display: "flex", 23 | columnGap: "4px", 24 | alignItems: "center", 25 | marginBottom: "16px" 26 | }; 27 | } 28 | 29 | export function checkboxTextStyle(theme : CometChatTheme) : CSSProperties { 30 | return { 31 | font: fontHelper(theme.typography.subtitle2), 32 | color: theme.palette.getAccent600("light") 33 | }; 34 | } 35 | 36 | export function submitBtnStyle(theme : CometChatTheme) : CSSProperties { 37 | return { 38 | font: fontHelper(theme.typography.subtitle1), 39 | color: theme.palette.getAccent900("light"), 40 | backgroundColor: theme.palette.getPrimary(), 41 | padding: "8px 4px", 42 | borderRadius: "8px", 43 | border: `1px solid ${theme.palette.getAccent100("light")}`, 44 | cursor: "pointer" 45 | }; 46 | } 47 | 48 | export function errorMessageStyle(theme : CometChatTheme) : CSSProperties { 49 | return { 50 | font: fontHelper(theme.typography.subtitle2), 51 | color: theme.palette.getError(), 52 | height: "48px", 53 | overflowY: "auto" 54 | }; 55 | } 56 | -------------------------------------------------------------------------------- /src/components/TextInput/index.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | inputStyle, 3 | labelContainerStyle, 4 | labelStyle, 5 | labelTextStyle, 6 | requiredSymbolStyle, 7 | } from "./style"; 8 | 9 | import { CometChatThemeContext } from "@cometchat/chat-uikit-react"; 10 | import { useContext } from "react"; 11 | 12 | interface ITextInputProps { 13 | labelText: string; 14 | placeholderText: string; 15 | value: string; 16 | onValueChange: (newValue: string) => void; 17 | required?: boolean; 18 | } 19 | 20 | export function TextInput(props: ITextInputProps) { 21 | const { 22 | labelText, 23 | placeholderText, 24 | value, 25 | onValueChange, 26 | required = false, 27 | } = props; 28 | 29 | const { theme } = useContext(CometChatThemeContext); 30 | 31 | function getLabel() { 32 | let labelJSX = {labelText}; 33 | if (required) { 34 | labelJSX = ( 35 | 36 | {labelJSX} 37 | * 38 | 39 | ); 40 | } 41 | return labelJSX; 42 | } 43 | 44 | return ( 45 | 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /src/components/TextInput/style.ts: -------------------------------------------------------------------------------- 1 | import { CSSProperties } from "react"; 2 | import { CometChatTheme, fontHelper } from "@cometchat/uikit-resources"; 3 | 4 | export function labelStyle() : CSSProperties { 5 | return { 6 | display: "flex", 7 | flexDirection: "column", 8 | rowGap: "4px" 9 | }; 10 | } 11 | 12 | export function labelTextStyle(theme : CometChatTheme) : CSSProperties { 13 | return { 14 | font: fontHelper(theme.typography.subtitle2), 15 | color: theme.palette.getAccent600("light") 16 | }; 17 | } 18 | 19 | export function inputStyle(theme : CometChatTheme) : CSSProperties { 20 | return { 21 | padding: "8px", 22 | border: `1px solid ${theme.palette.getAccent100("light")}`, 23 | borderRadius: "8px", 24 | font: fontHelper(theme.typography.subtitle2) 25 | }; 26 | } 27 | 28 | export function requiredSymbolStyle() : CSSProperties { 29 | return { 30 | color: "red" 31 | }; 32 | } 33 | 34 | export function labelContainerStyle() : CSSProperties { 35 | return { 36 | display: "flex", 37 | columnGap: "1px" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/const.ts: -------------------------------------------------------------------------------- 1 | export const CometChatConstants = { 2 | appId: "xxxxxxxxxxxxx", 3 | region: "xx", 4 | authKey: "xxxxxxxxxxxxxxxx", 5 | fcmProviderId: "xxxxxxxxxxx", 6 | }; 7 | -------------------------------------------------------------------------------- /src/custom-hooks.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from "react"; 2 | 3 | /** 4 | * Sets the created ref to the `value` passed 5 | * 6 | * @remarks 7 | * After the initial call of this hook, the internal ref is set to the `value` passed to this hook after the component has rendered completely. 8 | * So the returned ref will not have the updated value while the component renders 9 | */ 10 | export function useRefSync(value: T): React.MutableRefObject { 11 | const res = useRef(value); 12 | res.current = value; 13 | return res; 14 | } 15 | 16 | /** 17 | * Custom React hook for managing and retrieving query parameters from the current URL. 18 | * 19 | * @returns {Record} An object containing the query parameters where keys are parameter names and values are parameter values. 20 | * 21 | * @remarks 22 | * This hook parses the query parameters from the current URL and returns them as an object. It also removes the query parameters from the URL without affecting the browser history. 23 | * The returned object reflects the current query parameters after the component has rendered. 24 | */ 25 | 26 | export function useQueryParams(): Record { 27 | const [queryParams, setQueryParams] = useState>({}); 28 | 29 | useEffect(() => { 30 | const searchParams = new URL(window.location.href).searchParams; 31 | const params: Record = {}; 32 | 33 | searchParams.forEach((value, key) => { 34 | params[key] = value; 35 | }); 36 | 37 | if (Object.keys(params).length > 0) { 38 | // Remove the query parameters from the URL without affecting the browser history 39 | const urlWithoutQueryParams = window.location.href.replace( 40 | window.location.search, 41 | "" 42 | ); 43 | 44 | window.history.replaceState({}, document.title, urlWithoutQueryParams); 45 | } 46 | 47 | setQueryParams(params); 48 | }, []); 49 | 50 | return queryParams; 51 | } 52 | -------------------------------------------------------------------------------- /src/firebase.js: -------------------------------------------------------------------------------- 1 | 2 | import { initializeApp } from "firebase/app"; 3 | import { getMessaging, getToken, onMessage } from "firebase/messaging"; 4 | import { CometChatNotifications } from "@cometchat/chat-sdk-javascript"; 5 | import { CometChatConstants } from "./const"; 6 | export default async function firebaseInitialize(navigate) { 7 | const firebaseConfig = { 8 | apiKey: "xxxxxxxxxxxxxxxxxxxxx", 9 | authDomain: "xxxxxxxxxxxxxxxxxxxxx", 10 | projectId: "xxxxxxxxxxxxxxxxxxxxx", 11 | storageBucket: "xxxxxxxxxxxxxxxxxxxxx", 12 | messagingSenderId: "xxxxxxxxxxxxxxxxxxxxx", 13 | appId: "xxxxxxxxxxxxxxxxxxxxx", 14 | measurementId: "xxxxxxxxxxxxxxxxxxxxx" 15 | }; 16 | 17 | const app = initializeApp(firebaseConfig); // Initialize Firebase App 18 | const messaging = getMessaging(app); // Initialize Firebase Messaging 19 | 20 | getToken(messaging, { 21 | vapidKey: 22 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 23 | }) 24 | .then((currentToken) => { 25 | if (currentToken) { 26 | CometChatNotifications.registerPushToken( 27 | currentToken, 28 | CometChatNotifications.PushPlatforms.FCM_WEB, 29 | CometChatConstants.fcmProviderId 30 | ) 31 | .then((payload) => { 32 | console.log("from comet", payload); 33 | console.log("curr token", currentToken); 34 | }) 35 | .catch((err) => { 36 | console.log(err); 37 | }); 38 | } else { 39 | console.log( 40 | "No registration token available. Request permission to generate one." 41 | ); 42 | } 43 | }) 44 | .catch((err) => { 45 | console.log("An error occurred while retrieving token. ", err); 46 | }); 47 | 48 | onMessage(messaging, function (payload) { 49 | console.log("Got message",payload) 50 | }); 51 | } 52 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #root { 4 | height: 100%; 5 | } 6 | 7 | body { 8 | margin: 0; 9 | font-family: sans-serif; 10 | } 11 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import "./index.css"; 2 | 3 | import App from "./components/App/App"; 4 | import { BrowserRouter } from "react-router-dom"; 5 | import { CometChat } from "@cometchat/chat-sdk-javascript"; 6 | import { CometChatCalls } from "@cometchat/calls-sdk-javascript"; 7 | import { CometChatConstants } from "./const"; 8 | import { CometChatUIKit } from "@cometchat/chat-uikit-react"; 9 | import React from "react"; 10 | import ReactDOM from "react-dom/client"; 11 | import { UIKitSettingsBuilder } from "@cometchat/uikit-shared"; 12 | import reportWebVitals from "./reportWebVitals"; 13 | 14 | (async () => { 15 | const uiKitSettings = new UIKitSettingsBuilder() 16 | .setAppId(CometChatConstants.appId) 17 | .setRegion(CometChatConstants.region) 18 | .setAuthKey(CometChatConstants.authKey) 19 | .subscribePresenceForFriends() 20 | .build(); 21 | 22 | const callAppSetting = new CometChatCalls.CallAppSettingsBuilder() 23 | .setAppId(CometChatConstants.appId) 24 | .setRegion(CometChatConstants.region) 25 | .build(); 26 | 27 | try { 28 | CometChat.setDemoMetaInfo({ 29 | name: "push-notification-sample-app-javascript", 30 | platform: "react", 31 | type: "push-notification-sample-app-javascript", 32 | version: "0.1.1", 33 | }); 34 | await CometChatUIKit.init(uiKitSettings); 35 | await CometChatCalls.init(callAppSetting); 36 | console.log("Initialization completed successfully"); 37 | 38 | const root = ReactDOM.createRoot( 39 | document.getElementById("root") as HTMLElement 40 | ); 41 | 42 | root.render( 43 | 44 | 45 | 46 | ); 47 | askPermission(); 48 | } catch (error) { 49 | console.log("Initialization failed with error:", error); 50 | } 51 | })(); 52 | 53 | if ("serviceWorker" in navigator) { 54 | console.log("serviceWorker"); 55 | navigator.serviceWorker 56 | .register("/firebase-messaging-sw.js") 57 | 58 | .then(function (registration) { 59 | console.log("registration", registration); 60 | console.log("Registration succlgcessful, scope is:", registration.scope); 61 | }) 62 | .catch((error) => console.log("Registration error", error)); 63 | } 64 | 65 | async function askPermission() { 66 | return new Promise(function (resolve, reject) { 67 | const permissionResult = Notification.requestPermission(function (result) { 68 | resolve(result); 69 | }); 70 | 71 | if (permissionResult) { 72 | permissionResult.then(resolve, reject); 73 | } 74 | }).then(function (permissionResult) { 75 | if (permissionResult !== "granted") { 76 | console.log("Permission not granted"); 77 | } 78 | }); 79 | } 80 | 81 | reportWebVitals(); 82 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /src/reportWebVitals.ts: -------------------------------------------------------------------------------- 1 | import { ReportHandler } from 'web-vitals'; 2 | 3 | const reportWebVitals = (onPerfEntry?: ReportHandler) => { 4 | if (onPerfEntry && onPerfEntry instanceof Function) { 5 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 6 | getCLS(onPerfEntry); 7 | getFID(onPerfEntry); 8 | getFCP(onPerfEntry); 9 | getLCP(onPerfEntry); 10 | getTTFB(onPerfEntry); 11 | }); 12 | } 13 | }; 14 | 15 | export default reportWebVitals; 16 | -------------------------------------------------------------------------------- /src/sampleApp/sampledata.js: -------------------------------------------------------------------------------- 1 | import CaptainAmericaAvatar from "../assets/captainamerica_avatar.png"; 2 | import CyclopsAvatar from "../assets/cyclops_avatar.png"; 3 | import IronManAvatar from "../assets/ironman_avatar.png"; 4 | import SpidermanAvatar from "../assets/spiderman_avatar.png"; 5 | import WolverineAvatar from "../assets/wolverine_avatar.png"; 6 | 7 | export const users = { 8 | "users":[ 9 | { 10 | "uid": "superhero1", 11 | "name": "Iron Man", 12 | "avatar": IronManAvatar 13 | }, 14 | { 15 | "uid": "superhero2", 16 | "name": "Captain America", 17 | "avatar": CaptainAmericaAvatar 18 | }, 19 | { 20 | "uid": "superhero3", 21 | "name": "Spiderman", 22 | "avatar": SpidermanAvatar 23 | }, 24 | { 25 | "uid": "superhero4", 26 | "name": "Wolverine", 27 | "avatar": WolverineAvatar 28 | }, 29 | { 30 | "uid": "superhero5", 31 | "name": "Cyclops", 32 | "avatar": CyclopsAvatar 33 | } 34 | ] 35 | } -------------------------------------------------------------------------------- /src/setupTests.ts: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/subject.js: -------------------------------------------------------------------------------- 1 | import { Subject } from 'rxjs'; 2 | export const subject = new Subject(); 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | --------------------------------------------------------------------------------