From 8d21714f05592afc1189eb33d9f12aa554864b08 Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Tue, 9 May 2023 18:31:46 +0530 Subject: [PATCH 01/25] Style: fixed odia title (#104) * style: ui scroll bug on faq page * style: fixed odia title --- apps/amakrushi/lang/or.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/amakrushi/lang/or.json b/apps/amakrushi/lang/or.json index ba8f7fcf..2d7a170c 100644 --- a/apps/amakrushi/lang/or.json +++ b/apps/amakrushi/lang/or.json @@ -1,5 +1,5 @@ { - "label.title":"ଆମା କ୍ରୁଶ୍", + "label.title":"ଆମ କୃଷି", "label.welcome":"ସ୍ୱାଗତ", "label.chats":"ଚାଟ୍", "label.farmer":"କୃଷକ", From beec8fecb8e325fb3e4b6654127039fe4378491b Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Tue, 9 May 2023 20:59:13 +0530 Subject: [PATCH 02/25] Feat chat history (#106) fix: token authentication --- apps/amakrushi/.env.production | 17 +++++ .../PhoneView/ChatWindow/ChatUiWindow.tsx | 25 +------- .../components/chat-message-item/index.tsx | 2 + apps/amakrushi/src/hooks/index.ts | 3 +- apps/amakrushi/src/hooks/useLogin.ts | 62 +++++++++++++++++++ apps/amakrushi/src/pages/_app.tsx | 60 ++++++++---------- turbo.json | 1 - 7 files changed, 113 insertions(+), 57 deletions(-) create mode 100644 apps/amakrushi/.env.production create mode 100644 apps/amakrushi/src/hooks/useLogin.ts diff --git a/apps/amakrushi/.env.production b/apps/amakrushi/.env.production new file mode 100644 index 00000000..1083a5b9 --- /dev/null +++ b/apps/amakrushi/.env.production @@ -0,0 +1,17 @@ +#NEXT_PUBLIC_OTP_BASE_URL = 'https://user-service.chakshu-rd.samagra.io/' +NEXT_PUBLIC_OTP_BASE_URL = 'https://user-service.staging.akai.samagra.io/' +NEXT_PUBLIC_FIREBASE_API_KEY = 'AIzaSyC8HKDeYrdYQgPeU2EWgAjBUoIXBcDWWDs' +NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN = 'amakrushai-c0799.firebaseapp.com' +NEXT_PUBLIC_FIREBASE_PROJECT_ID = 'amakrushai-c0799' +NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET = 'amakrushai-c0799.appspot.com' +NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID = '609958354974' +NEXT_PUBLIC_FIREBASE_APP_ID = '1:609958354974:web:32cdefc4dc7fd7a0198e0f' +NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID = 'G-28FVJBEET6' +NEXT_PUBLIC_ENVIRONMENT_ID = "UcMPF6pf85uaR2h3ajFr3R" +NEXT_PUBLIC_BASE_URL = 'https://staging.akai.samagra.io' +#NEXT_PUBLIC_JWT_CERT = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmPw09w/sAcleZy+A4XJs\nncT2oYZv5I3f4vQ/Pucet1EKrgpxRsZF1KFQLM29+9d29BJvAMevpz8dHoyb/S4/\nCOurBFSnDkrKTa9Zl9y7K4Udq6dtjCOL+WHaDdeHVHXYI/c8U3eq5YStM/PWjWX5\nr3TsQ2OniFrLNMJaNdGg72kj3YrvJYf5AaGyE9JrMrfTxxyLrnERULjvZkHCXthQ\njXld7bpL3gMOlzDDrScIQsEVSAOOSzaxu47tvoBC7JALyOe127YneKTCKuTLd4Mp\nBhDJeg9x3UvKydoGmHTc1ckPEW7rJHU3DJ+Llwvgk5QE895fVBOSwTGRzz31YFdD\nswIDAQAB\n-----END PUBLIC KEY-----" +NEXT_PUBLIC_JWT_CERT = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmPw09w/sAcleZy+A4XJs\nncT2oYZv5I3f4vQ/Pucet1EKrgpxRsZF1KFQLM29+9d29BJvAMevpz8dHoyb/S4/\nCOurBFSnDkrKTa9Zl9y7K4Udq6dtjCOL+WHaDdeHVHXYI/c8U3eq5YStM/PWjWX5\nr3TsQ2OniFrLNMJaNdGg72kj3YrvJYf5AaGyE9JrMrfTxxyLrnERULjvZkHCXthQ\njXld7bpL3gMOlzDDrScIQsEVSAOOSzaxu47tvoBC7JALyOe127YneKTCKuTLd4Mp\nBhDJeg9x3UvKydoGmHTc1ckPEW7rJHU3DJ+Llwvgk5QE895fVBOSwTGRzz31YFdD\nswIDAQAB\n-----END PUBLIC KEY-----" +NEXT_PUBLIC_SOCKET_URL = "wss://ts.staging.akai.samagra.io" +#NEXT_PUBLIC_SOCKET_URL = "wss://ts.gpt3.samagra.io" +NEXT_PUBLIC_USER_SERVICE_APP_ID = "7a6c82e9-d539-4de9-8f58-3dde67894dde" +NEXT_PUBLIC_JWKS_URI = "https://fusionauth.staging.akai.samagra.io/.well-known/jwks.json" \ No newline at end of file diff --git a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx index a9e609c2..5d504305 100644 --- a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx +++ b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx @@ -18,7 +18,9 @@ import { useLocalization } from '../../../hooks'; import { getMsgType } from '../../../utils/getMsgType'; import ChatMessageItem from '../../chat-message-item'; import { v4 as uuidv4 } from 'uuid'; +import toast from 'react-hot-toast'; const ChatUiWindow: React.FC = () => { + const t = useLocalization(); const context = useContext(AppContext); const router = useRouter(); @@ -76,28 +78,7 @@ const ChatUiWindow: React.FC = () => { return history; }; - useEffect(() => { - if (cookies['access_token'] !== undefined) { - axios - .get(`/api/auth?token=${cookies['access_token']}`) - .then((response) => { - if (response.data === null) { - throw 'Invalid Access Token'; - // // router.push("/login"); - } - }) - .catch((err) => { - //@ts-ignore - logEvent(analytics, 'console_error', { - error_message: err.message, - }); - throw err; - }); - setAccessToken(cookies['access_token']); - } else { - router.push('/login'); - } - }, [cookies, router]); + const handleSend = useCallback( (type: string, val: any) => { diff --git a/apps/amakrushi/src/components/chat-message-item/index.tsx b/apps/amakrushi/src/components/chat-message-item/index.tsx index 46ff2878..5b51d467 100644 --- a/apps/amakrushi/src/components/chat-message-item/index.tsx +++ b/apps/amakrushi/src/components/chat-message-item/index.tsx @@ -52,9 +52,11 @@ const ChatMessageItem: FC = ({ useEffect(() => { setReaction(message?.content?.data?.reaction); + }, [message?.content?.data?.reaction]); + const onLikeDislike = useCallback( ({ value, msgId }: { value: 0 | 1 | -1; msgId: string }) => { let url = getReactionUrl({ msgId, reaction: value }); diff --git a/apps/amakrushi/src/hooks/index.ts b/apps/amakrushi/src/hooks/index.ts index 61ac345d..f7510ccb 100644 --- a/apps/amakrushi/src/hooks/index.ts +++ b/apps/amakrushi/src/hooks/index.ts @@ -1,2 +1,3 @@ export * from './useLocalization' -export * from './useLocalStorage' \ No newline at end of file +export * from './useLocalStorage' +export * from './useLogin' \ No newline at end of file diff --git a/apps/amakrushi/src/hooks/useLogin.ts b/apps/amakrushi/src/hooks/useLogin.ts new file mode 100644 index 00000000..72d59d86 --- /dev/null +++ b/apps/amakrushi/src/hooks/useLogin.ts @@ -0,0 +1,62 @@ +import axios from 'axios'; +import { useCallback, useEffect, useState } from 'react'; +import { useCookies } from 'react-cookie'; +import jwt from 'jsonwebtoken'; +import { useRouter } from 'next/router'; +import toast from 'react-hot-toast'; +import { analytics } from '../utils/firebase'; +import { logEvent } from 'firebase/analytics'; + +type User = { + username: string; + expiredAt: number; + accessToken: string; + avatar?: string; + id: string; +}; + +export const useLogin = () => { + const [cookies, setCookie, removeCookie] = useCookies(['access_token']); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const router = useRouter(); + + const login = useCallback(() => { + // No need to check for auth if access token is not present + if (cookies.access_token) { + const decodedToken = jwt.decode(cookies.access_token); + const expires = new Date(decodedToken?.exp * 1000); + // if token not expired then check for auth + if (expires > new Date()) { + const token = cookies.access_token; + axios + .get(`/api/auth?token=${token}`) + .then((response) => { + if (response.data === null) { + toast.error('Invalid Access Token'); + router.push('/login'); + console.log('response null'); + } else { + setIsAuthenticated(true); + console.log('authenticated true'); + } + }) + .catch((err) => { + //@ts-ignore + logEvent(analytics, 'console_error', { + error_message: err.message, + }); + router.push('/login'); + console.log('catch err'); + }); + } else { + removeCookie('access_token', { path: '/' }); + localStorage.clear(); + sessionStorage.clear(); + router.push('/login'); + if (typeof window !== 'undefined') window.location.reload(); + } + } + }, [cookies.access_token, removeCookie, router]); + + return { isAuthenticated, login }; +}; diff --git a/apps/amakrushi/src/pages/_app.tsx b/apps/amakrushi/src/pages/_app.tsx index 96ad3577..903c60b0 100644 --- a/apps/amakrushi/src/pages/_app.tsx +++ b/apps/amakrushi/src/pages/_app.tsx @@ -1,23 +1,23 @@ -import "../styles/globals.css"; -import type { AppProps } from "next/app"; -import { ChakraProvider } from "@chakra-ui/react"; -import jwt from 'jsonwebtoken'; -import ContextProvider from "../context/ContextProvider"; -import { ReactElement, useCallback, useEffect, useState } from "react"; -import "chatui/dist/index.css"; -import { Toaster } from "react-hot-toast"; +import '../styles/globals.css'; +import type { AppProps } from 'next/app'; +import { ChakraProvider } from '@chakra-ui/react'; +import ContextProvider from '../context/ContextProvider'; +import { ReactElement, useCallback, useEffect, useState } from 'react'; +import 'chatui/dist/index.css'; +import { Toaster } from 'react-hot-toast'; -import { useCookies } from "react-cookie"; -import { useRouter } from "next/router"; -import dynamic from "next/dynamic"; +import { useCookies } from 'react-cookie'; +import { useRouter } from 'next/router'; +import dynamic from 'next/dynamic'; -import flagsmith from "flagsmith/isomorphic"; -import { FlagsmithProvider } from "flagsmith/react"; +import flagsmith from 'flagsmith/isomorphic'; +import { FlagsmithProvider } from 'flagsmith/react'; +import { useLogin } from '../hooks'; -const LaunchPage = dynamic(() => import("../components/LaunchPage"), { +const LaunchPage = dynamic(() => import('../components/LaunchPage'), { ssr: false, }); -const NavBar = dynamic(() => import("../components/NavBar"), { +const NavBar = dynamic(() => import('../components/NavBar'), { ssr: false, }); function SafeHydrate({ children }: { children: ReactElement }) { @@ -34,6 +34,7 @@ const App = ({ flagsmithState, }: AppProps & { flagsmithState: any }) => { const router = useRouter(); + const { isAuthenticated, login } = useLogin(); const [launch, setLaunch] = useState(true); const [cookie, setCookie, removeCookie] = useCookies(); useEffect(() => { @@ -42,17 +43,6 @@ const App = ({ }, 2500); }, []); - const handleTokenExpiration = useCallback(() => { - const decodedToken = jwt.decode(cookie['access_token']); - const expires = new Date(decodedToken?.exp * 1000); - if (expires < new Date()) { - removeCookie('access_token', { path: '/' }); - router.push('/login'); - return; - } - - }, [cookie, removeCookie, router]); - const handleLoginRedirect = useCallback(() => { if (router.pathname === "/login" || router.pathname.startsWith("/otp")) { // already logged in then send to home @@ -68,14 +58,18 @@ const App = ({ } } }, [cookie, router]); - + useEffect(() => { - handleTokenExpiration(); handleLoginRedirect(); - }, [handleTokenExpiration, handleLoginRedirect]); - + }, [handleLoginRedirect]); + + useEffect(() => { + if(!isAuthenticated){ + login(); + } + }, [isAuthenticated, login]); - if (process.env.NODE_ENV === "production") { + if (process.env.NODE_ENV === 'production') { globalThis.console.log = () => {}; } @@ -86,8 +80,8 @@ const App = ({ -
- +
+ diff --git a/turbo.json b/turbo.json index 6a43da99..9acd1ac7 100644 --- a/turbo.json +++ b/turbo.json @@ -11,7 +11,6 @@ "NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID", "NEXT_PUBLIC_FIREBASE_APP_ID", "NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID", - "NEXT_PUBLIC_JWT_CERT", "ANALYZE", "NEXT_PUBLIC_ENVIRONMENT_ID", "NEXT_PUBLIC_BASE_URL", From 69137b3b0930607b55bab0a0ab7ac36893e0ac22 Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Tue, 9 May 2023 21:22:48 +0530 Subject: [PATCH 03/25] Delete .env.production --- apps/amakrushi/.env.production | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 apps/amakrushi/.env.production diff --git a/apps/amakrushi/.env.production b/apps/amakrushi/.env.production deleted file mode 100644 index 1083a5b9..00000000 --- a/apps/amakrushi/.env.production +++ /dev/null @@ -1,17 +0,0 @@ -#NEXT_PUBLIC_OTP_BASE_URL = 'https://user-service.chakshu-rd.samagra.io/' -NEXT_PUBLIC_OTP_BASE_URL = 'https://user-service.staging.akai.samagra.io/' -NEXT_PUBLIC_FIREBASE_API_KEY = 'AIzaSyC8HKDeYrdYQgPeU2EWgAjBUoIXBcDWWDs' -NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN = 'amakrushai-c0799.firebaseapp.com' -NEXT_PUBLIC_FIREBASE_PROJECT_ID = 'amakrushai-c0799' -NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET = 'amakrushai-c0799.appspot.com' -NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID = '609958354974' -NEXT_PUBLIC_FIREBASE_APP_ID = '1:609958354974:web:32cdefc4dc7fd7a0198e0f' -NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID = 'G-28FVJBEET6' -NEXT_PUBLIC_ENVIRONMENT_ID = "UcMPF6pf85uaR2h3ajFr3R" -NEXT_PUBLIC_BASE_URL = 'https://staging.akai.samagra.io' -#NEXT_PUBLIC_JWT_CERT = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmPw09w/sAcleZy+A4XJs\nncT2oYZv5I3f4vQ/Pucet1EKrgpxRsZF1KFQLM29+9d29BJvAMevpz8dHoyb/S4/\nCOurBFSnDkrKTa9Zl9y7K4Udq6dtjCOL+WHaDdeHVHXYI/c8U3eq5YStM/PWjWX5\nr3TsQ2OniFrLNMJaNdGg72kj3YrvJYf5AaGyE9JrMrfTxxyLrnERULjvZkHCXthQ\njXld7bpL3gMOlzDDrScIQsEVSAOOSzaxu47tvoBC7JALyOe127YneKTCKuTLd4Mp\nBhDJeg9x3UvKydoGmHTc1ckPEW7rJHU3DJ+Llwvgk5QE895fVBOSwTGRzz31YFdD\nswIDAQAB\n-----END PUBLIC KEY-----" -NEXT_PUBLIC_JWT_CERT = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmPw09w/sAcleZy+A4XJs\nncT2oYZv5I3f4vQ/Pucet1EKrgpxRsZF1KFQLM29+9d29BJvAMevpz8dHoyb/S4/\nCOurBFSnDkrKTa9Zl9y7K4Udq6dtjCOL+WHaDdeHVHXYI/c8U3eq5YStM/PWjWX5\nr3TsQ2OniFrLNMJaNdGg72kj3YrvJYf5AaGyE9JrMrfTxxyLrnERULjvZkHCXthQ\njXld7bpL3gMOlzDDrScIQsEVSAOOSzaxu47tvoBC7JALyOe127YneKTCKuTLd4Mp\nBhDJeg9x3UvKydoGmHTc1ckPEW7rJHU3DJ+Llwvgk5QE895fVBOSwTGRzz31YFdD\nswIDAQAB\n-----END PUBLIC KEY-----" -NEXT_PUBLIC_SOCKET_URL = "wss://ts.staging.akai.samagra.io" -#NEXT_PUBLIC_SOCKET_URL = "wss://ts.gpt3.samagra.io" -NEXT_PUBLIC_USER_SERVICE_APP_ID = "7a6c82e9-d539-4de9-8f58-3dde67894dde" -NEXT_PUBLIC_JWKS_URI = "https://fusionauth.staging.akai.samagra.io/.well-known/jwks.json" \ No newline at end of file From 61e535faf1086b8790aca76535ac3044f7216be1 Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 11 May 2023 00:33:44 +0530 Subject: [PATCH 04/25] UI changes (#112) * style: minor ui changes * fix: delete history page fix and flagsmith self hoasted added --------- Co-authored-by: Prateek Jakhar --- apps/amakrushi/lang/en.json | 2 + apps/amakrushi/lang/or.json | 2 + .../components/HistoryPage/index.module.css | 24 ++++++++ .../src/components/HistoryPage/index.tsx | 47 ++++++++++----- .../src/components/MorePage/FAQPage/index.tsx | 2 +- .../src/components/chat-item/index.tsx | 57 ++++++++++--------- .../chat-message-item/index.module.css | 28 +++++++++ .../components/chat-message-item/index.tsx | 54 +++++++++++------- apps/amakrushi/src/pages/_app.tsx | 5 +- apps/amakrushi/src/types/chat-item/index.d.ts | 1 + turbo.json | 1 + 11 files changed, 163 insertions(+), 60 deletions(-) diff --git a/apps/amakrushi/lang/en.json b/apps/amakrushi/lang/en.json index 05d82a88..f3668bfe 100644 --- a/apps/amakrushi/lang/en.json +++ b/apps/amakrushi/lang/en.json @@ -21,6 +21,8 @@ "label.click":"Reload", "label.new_chat":"New chat", "label.confirm_delete":"Are you sure you want to delete this conversation?", + "label.no_history":"No Chats", + "message.no_history":"Your Chat History with AI will come here", "message.socket_disconnect_msg": "to connect again.", "message.enter_mobile":"Enter Mobile Number", "message.register_message":"If you are already registered then use your mobile number to login.", diff --git a/apps/amakrushi/lang/or.json b/apps/amakrushi/lang/or.json index 2d7a170c..448f224d 100644 --- a/apps/amakrushi/lang/or.json +++ b/apps/amakrushi/lang/or.json @@ -21,6 +21,8 @@ "label.click":"ସତେଜ କରନ୍ତୁ", "label.new_chat":"ନୂଆ ଚାଟ୍", "label.confirm_delete":"ଆପଣ ନିଶ୍ଚିତ କି ଆପଣ ଏହି ବାର୍ତ୍ତାଳାପକୁ ବିଲୋପ କରିବାକୁ ଚାହୁଁଛନ୍ତି?", + "label.no_history":"କ chat ଣସି ଚାଟ୍ ନାହିଁ |", + "message.no_history":"AI ସହିତ ଆପଣଙ୍କର ଚାଟ୍ ଇତିହାସ ଏଠାକୁ ଆସିବ |", "message.socket_disconnect_msg": "ପୁନର୍ବାର ସଂଯୋଗ କରିବାକୁ |", "message.enter_mobile":"ମୋବାଇଲ୍ ନମ୍ବର ପ୍ରବେଶ କରନ୍ତୁ |", "message.register_message":"ଯୋଡି ଆପଣ ପୂର୍ବରୁ ପଞ୍ଜୀକୃତ ହୋଇଛନ୍ତି ତେବେ ଲଗଇନ୍ କରିବା ପାଇଁ ଆପଣଙ୍କର ମୋବାଇଲ ନମ୍ବର ବ୍ୟବହାର କରନ୍ତୁ |", diff --git a/apps/amakrushi/src/components/HistoryPage/index.module.css b/apps/amakrushi/src/components/HistoryPage/index.module.css index a68da0a1..15ae8191 100644 --- a/apps/amakrushi/src/components/HistoryPage/index.module.css +++ b/apps/amakrushi/src/components/HistoryPage/index.module.css @@ -31,4 +31,28 @@ font-size: 4.265vh; font-weight: 700; color: var(--secondarygreen); +} + +.noHistory{ + height: 35vh; + display: flex; + flex-direction: column; + justify-content: center; +} + +.noHistory div{ + margin-top: 4vh; + margin-left: 2vh; + font-family: 'Mulish-Bold'; + font-size: 4vh; + text-align: center; + color: var(--grey); +} +.noHistory p{ + margin-top: 4vh; + margin-left: 2vh; + font-family: 'Mulish-Bold'; + font-size: 1.65vh; + text-align: center; + color: var(--secondarygreen); } \ No newline at end of file diff --git a/apps/amakrushi/src/components/HistoryPage/index.tsx b/apps/amakrushi/src/components/HistoryPage/index.tsx index d28ce466..37ba6126 100644 --- a/apps/amakrushi/src/components/HistoryPage/index.tsx +++ b/apps/amakrushi/src/components/HistoryPage/index.tsx @@ -1,5 +1,5 @@ import styles from './index.module.css'; -import React, { useEffect, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import searchIcon from '../../assets/icons/search.svg'; import { Input, InputGroup, InputLeftElement } from '@chakra-ui/react'; import ChatItem from '../chat-item'; @@ -31,13 +31,16 @@ const HistoryPage: NextPage = () => { }/user/conversations/${localStorage.getItem('userID')}` ) .then((res) => { - const sortedConversations = _.filter(res?.data,conv=>conv?.conversationId !==null).sort( + const sortedConversations = _.filter( + res?.data, + (conv) => conv?.conversationId !== null + ).sort( //@ts-ignore (a, b) => new Date(b.createdAt) - new Date(a.createdAt) ); - //@ts-ignore + //@ts-ignore setConversations(sortedConversations); - console.log('conversations:', sortedConversations); + console.log('hie', sortedConversations); }) .catch((error) => { //@ts-ignore @@ -47,6 +50,16 @@ const HistoryPage: NextPage = () => { }); }, []); + // Function to delete conversation by conversationId + const deleteConversationById = useCallback((conversationIdToDelete: any) => { + const filteredConversations = [...conversations].filter( + (conversation: any) => conversation.conversationId !== conversationIdToDelete + ); + setConversations(filteredConversations); + }, [conversations]); + + + if (!flags?.show_chat_history_page?.enabled) { return ; } else @@ -61,15 +74,23 @@ const HistoryPage: NextPage = () => { */}
- {conversations.map((conv:any, key) => { - return ( - - ); - })} + {conversations.length > 0 + ? conversations.map((conv: any) => { + return ( + + ); + }) + : ( +
+
{t('label.no_history')}
+

{t('message.no_history')}

+
+ )}
diff --git a/apps/amakrushi/src/components/MorePage/FAQPage/index.tsx b/apps/amakrushi/src/components/MorePage/FAQPage/index.tsx index 9b1b66d3..848d5977 100644 --- a/apps/amakrushi/src/components/MorePage/FAQPage/index.tsx +++ b/apps/amakrushi/src/components/MorePage/FAQPage/index.tsx @@ -158,7 +158,7 @@ const FAQPage: React.FC = () => {
{t('message.dial_description')}
- +
callIcon
diff --git a/apps/amakrushi/src/components/chat-item/index.tsx b/apps/amakrushi/src/components/chat-item/index.tsx index 2b623b9c..8fe7feca 100644 --- a/apps/amakrushi/src/components/chat-item/index.tsx +++ b/apps/amakrushi/src/components/chat-item/index.tsx @@ -12,7 +12,11 @@ import { v4 as uuidv4 } from 'uuid'; import { AppContext } from '../../context'; import { useLocalization } from '../../hooks'; -const ChatItem: React.FC = ({ name, conversationId }) => { +const ChatItem: React.FC = ({ + name, + conversationId, + deleteConversationById, +}) => { const context = useContext(AppContext); const t = useLocalization(); const [isConversationDeleted, setIsConversationDeleted] = useState(false); @@ -24,34 +28,35 @@ const ChatItem: React.FC = ({ name, conversationId }) => { }, [context, conversationId]); const deleteConversation = useCallback(() => { - const confirmed = window?.confirm(`${t("label.confirm_delete")}`); - if(confirmed){ + const confirmed = window?.confirm(`${t('label.confirm_delete')}`); + if (confirmed) { axios - .get( - `${ - process.env.NEXT_PUBLIC_BASE_URL - }/user/conversations/delete/${localStorage.getItem( - 'userID' - )}/${conversationId}` - ) - .then((res) => { - console.log('deleting conversation') - if (conversationId === sessionStorage.getItem('conversationId')) { - const newConversationId= uuidv4(); - sessionStorage.setItem('conversationId',newConversationId); - context?.setConversationId(newConversationId); - context?.setMessages([]); - } - setIsConversationDeleted(true); - }) - .catch((error) => { - //@ts-ignore - logEvent(analytics, 'console_error', { - error_message: error.message, + .get( + `${ + process.env.NEXT_PUBLIC_BASE_URL + }/user/conversations/delete/${localStorage.getItem( + 'userID' + )}/${conversationId}` + ) + .then((res) => { + console.log('deleting conversation'); + if (conversationId === sessionStorage.getItem('conversationId')) { + const newConversationId = uuidv4(); + sessionStorage.setItem('conversationId', newConversationId); + context?.setConversationId(newConversationId); + context?.setMessages([]); + } + deleteConversationById(conversationId); + setIsConversationDeleted(true); + }) + .catch((error) => { + //@ts-ignore + logEvent(analytics, 'console_error', { + error_message: error.message, + }); }); - }); } - }, [context, conversationId, t]); + }, [context, conversationId, deleteConversationById, t]); return ( <> diff --git a/apps/amakrushi/src/components/chat-message-item/index.module.css b/apps/amakrushi/src/components/chat-message-item/index.module.css index 86e2b2fd..469dfa9a 100644 --- a/apps/amakrushi/src/components/chat-message-item/index.module.css +++ b/apps/amakrushi/src/components/chat-message-item/index.module.css @@ -1,3 +1,31 @@ +.messageTriangleRight { + content: ' '; + margin-right: 1vh; + position: absolute; + width: 0; + height: 0; + left: auto; + right: -20px; + top: 0px; + bottom: auto; + border: 20px solid; + border-color: var(--secondarygreen) transparent transparent transparent; +} + +.messageTriangleLeft { + margin-left: 1vh; + content: ' '; + position: absolute; + width: 0; + height: 0; + left: -20px; + right: auto; + top: 0px; + bottom: auto; + border: 22px solid; + border-color: white transparent transparent transparent; +} + .onHover { font-weight: bold; color: var(--secondarygreen); diff --git a/apps/amakrushi/src/components/chat-message-item/index.tsx b/apps/amakrushi/src/components/chat-message-item/index.tsx index 5b51d467..0bf91baa 100644 --- a/apps/amakrushi/src/components/chat-message-item/index.tsx +++ b/apps/amakrushi/src/components/chat-message-item/index.tsx @@ -32,39 +32,44 @@ import { ChatMessageItemPropType } from '../../types'; import { getFormatedTime } from '../../utils/getUtcTime'; import { useLocalization } from '../../hooks/useLocalization'; import { getReactionUrl } from '../../utils/getUrls'; +import { useFlags } from 'flagsmith/react'; - -const getToastMessage=(t:any,reaction:number):string=>{ - if(reaction===1) - return t('toast.reaction_like'); - if(reaction===-1) - return t('toast.reaction_dislike') - return t('toast.reaction_reset') -} +const getToastMessage = (t: any, reaction: number): string => { + if (reaction === 1) return t('toast.reaction_like'); + if (reaction === -1) return ''; + return t('toast.reaction_reset'); +}; const ChatMessageItem: FC = ({ currentUser, message, onSend, }) => { + const flags = useFlags(['dialer_number']); const t = useLocalization(); const context = useContext(AppContext); const [reaction, setReaction] = useState(message?.content?.data?.reaction); - + useEffect(() => { setReaction(message?.content?.data?.reaction); - - }, [message?.content?.data?.reaction]); - - + }, [message?.content?.data?.reaction]); const onLikeDislike = useCallback( ({ value, msgId }: { value: 0 | 1 | -1; msgId: string }) => { let url = getReactionUrl({ msgId, reaction: value }); - + axios .get(url) .then((res: any) => { - toast.success(`${getToastMessage(t,value)}`); + if (value === -1) { + const dial = window?.confirm( + `Please call ${flags.dialer_number.value} to resolve your query with Ama Krushi Call centre` + ); + if (dial) { + const anchor = document.createElement('a'); + anchor.href = `tel:${flags.dialer_number.value}`; + anchor.click(); + } + } else toast.success(`${getToastMessage(t, value)}`); }) .catch((error: any) => { //@ts-ignore @@ -73,7 +78,7 @@ const ChatMessageItem: FC = ({ }); }); }, - [t] + [flags.dialer_number.value, t] ); const feedbackHandler = useCallback( @@ -100,7 +105,7 @@ const ChatMessageItem: FC = ({ }, [onLikeDislike, reaction] ); - + const getLists = useCallback( ({ choices, isDisabled }: { choices: any; isDisabled: boolean }) => { console.log('qwer12:', { choices, isDisabled }); @@ -118,7 +123,7 @@ const ChatMessageItem: FC = ({ toast.error(`${t('message.cannot_answer_again')}`); } else { if (context?.messages?.[0]?.exampleOptions) { - console.log('clearing chat') + console.log('clearing chat'); context?.setMessages([]); } context?.sendMessage(choice.text); @@ -145,7 +150,18 @@ const ChatMessageItem: FC = ({ return ; case 'text': return ( -
+
+
{ + console.log("asdfg:",{flagsmithState}) const router = useRouter(); const { isAuthenticated, login } = useLogin(); const [launch, setLaunch] = useState(true); @@ -96,7 +97,9 @@ const App = ({ App.getInitialProps = async () => { await flagsmith.init({ - environmentID: process.env.NEXT_PUBLIC_ENVIRONMENT_ID, + api:process.env.NEXT_PUBLIC_FLAGSMITH_API, + environmentID: process.env.NEXT_PUBLIC_ENVIRONMENT_ID + }); return { flagsmithState: flagsmith.getState() }; }; diff --git a/apps/amakrushi/src/types/chat-item/index.d.ts b/apps/amakrushi/src/types/chat-item/index.d.ts index 9cfe745d..51c02085 100644 --- a/apps/amakrushi/src/types/chat-item/index.d.ts +++ b/apps/amakrushi/src/types/chat-item/index.d.ts @@ -1,4 +1,5 @@ export type ChatItemPropsType = { name: string; conversationId: string | null; + deleteConversationById: any; }; diff --git a/turbo.json b/turbo.json index 9acd1ac7..01015172 100644 --- a/turbo.json +++ b/turbo.json @@ -11,6 +11,7 @@ "NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID", "NEXT_PUBLIC_FIREBASE_APP_ID", "NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID", + "NEXT_PUBLIC_FLAGSMITH_API", "ANALYZE", "NEXT_PUBLIC_ENVIRONMENT_ID", "NEXT_PUBLIC_BASE_URL", From fb95fbc07465c688a7a59c9324b2bbb0f9706daf Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 11 May 2023 17:35:34 +0530 Subject: [PATCH 05/25] fix: conversation id (#115) * fix: conversation id --- apps/amakrushi/src/context/ContextProvider.tsx | 3 ++- apps/amakrushi/src/pages/_app.tsx | 1 + apps/amakrushi/src/pages/api/sha.js | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 apps/amakrushi/src/pages/api/sha.js diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index c911049e..e496e552 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -111,7 +111,8 @@ const ContextProvider: FC<{ sentTimestamp: Date.now(), ...media, }; - + //@ts-ignore + if(conversationId===msg?.content?.conversationId) setMessages((prev: any) => _.uniq([...prev, newMsg], ['messageId'])); } diff --git a/apps/amakrushi/src/pages/_app.tsx b/apps/amakrushi/src/pages/_app.tsx index f4524c15..79571f91 100644 --- a/apps/amakrushi/src/pages/_app.tsx +++ b/apps/amakrushi/src/pages/_app.tsx @@ -13,6 +13,7 @@ import dynamic from 'next/dynamic'; import flagsmith from 'flagsmith/isomorphic'; import { FlagsmithProvider } from 'flagsmith/react'; import { useLogin } from '../hooks'; +import axios from 'axios'; const LaunchPage = dynamic(() => import('../components/LaunchPage'), { ssr: false, diff --git a/apps/amakrushi/src/pages/api/sha.js b/apps/amakrushi/src/pages/api/sha.js new file mode 100644 index 00000000..55c8138e --- /dev/null +++ b/apps/amakrushi/src/pages/api/sha.js @@ -0,0 +1,15 @@ + + + +export default function handler(req, res) { + const shaFull = require('child_process').execSync(`git rev-parse HEAD`).toString().trim(); + + switch (req.method) { + case "GET":{ + res.send(shaFull); + } + return; + default: + return res.status(405).end(`Method ${req.method} Not allowed`); + } +} \ No newline at end of file From f9192d48a19d25745de1ed0c9001864981baf709 Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Thu, 11 May 2023 22:39:31 +0530 Subject: [PATCH 06/25] Added down time page (#117) --- apps/amakrushi/lang/en.json | 3 + apps/amakrushi/lang/or.json | 3 + apps/amakrushi/src/assets/icons/down-time.svg | 9 ++ .../src/components/HomePage/index.module.css | 1 + .../src/components/HomePage/index.tsx | 2 + .../amakrushi/src/components/NavBar/index.tsx | 2 +- .../PhoneView/ChatWindow/ChatUiWindow.tsx | 117 +++++++++--------- .../components/chat-message-item/index.tsx | 20 +-- .../down-time-page/index.module.css | 48 +++++++ .../src/components/down-time-page/index.tsx | 30 +++++ .../amakrushi/src/context/ContextProvider.tsx | 67 ++++++---- apps/amakrushi/src/pages/_app.tsx | 1 - apps/amakrushi/src/pages/api/auth.js | 2 +- 13 files changed, 209 insertions(+), 96 deletions(-) create mode 100644 apps/amakrushi/src/assets/icons/down-time.svg create mode 100644 apps/amakrushi/src/components/down-time-page/index.module.css create mode 100644 apps/amakrushi/src/components/down-time-page/index.tsx diff --git a/apps/amakrushi/lang/en.json b/apps/amakrushi/lang/en.json index f3668bfe..e5aff6e6 100644 --- a/apps/amakrushi/lang/en.json +++ b/apps/amakrushi/lang/en.json @@ -42,6 +42,7 @@ "message.wait_resending_otp": "Please wait before resending OTP", "message.helpful": "Was this helpful?", "message.retry":"Please retry.", + "message.down_time_retry":"Retry", "message.taking_longer":"Please wait, servers are taking longer than usual.", "message.rating_submitted": "Rating Submitted!", "message.review_submitted": "Review Submitted!", @@ -54,6 +55,8 @@ "message.rating_description" : "Tap a star to rate", "message.review": "Write your review (optional)", "message.review_description": "Please write your experience's feedback.", + "message.temporarily_down": "We're temporarily down", + "message.temporarily_down_description": "We are experiencing high user volume at the moment, please try logging in after some time", "error.fail_to_submit":"Failed to submit rating.", "error.fail_to_submit_review": "Failed to submit review.", "error.sending_otp":"Error sending OTP", diff --git a/apps/amakrushi/lang/or.json b/apps/amakrushi/lang/or.json index 448f224d..7f424d3b 100644 --- a/apps/amakrushi/lang/or.json +++ b/apps/amakrushi/lang/or.json @@ -42,6 +42,7 @@ "message.wait_resending_otp": "OTP ପଠାଇବା ପୂର୍ବରୁ ଦୟାକରି ଅପେକ୍ଷା କରନ୍ତୁ |", "message.helpful": "ଏହା ସାହାଯ୍ୟକାରୀ ଥିଲା କି?", "message.retry":"ପୁନର୍ବାର ଚେଷ୍ଟା କରନ୍ତୁ", + "message.down_time_retry": "ପୂର୍ଣ୍ଣବାର ଚେଷ୍ଟା କରନ୍ତୁ", "message.taking_longer":"ଦୟାକରି ଅପେକ୍ଷା କରନ୍ତୁ, ସର୍ଭର୍ ସାଧାରଣ ସମୟ ରୁ ଅଧିକ ସମୟ ନେଉଛି", "message.rating_submitted": "ମୂଲ୍ୟାୟନ ଦାଖଲ!", "message.review_submitted": "ସମୀକ୍ଷା ଦାଖଲ!", @@ -55,6 +56,8 @@ "message.rating_description" : "ରେଟ୍ କରିବାକୁ ଏକ ତାରକା ଟ୍ୟାପ୍ କରନ୍ତୁ |", "message.review": "ଆପଣଙ୍କର ସମୀକ୍ଷା ଲେଖନ୍ତୁ (ବ al କଳ୍ପିକ)", "message.review_description": "ଦୟାକରି ଆପଣଙ୍କର ଅଭିଜ୍ଞତା ମତାମତ ଲେଖନ୍ତୁ |", + "message.temporarily_down": "କିଛି ସମୟ ପାଇଁ ସର୍ଭର ଡାଉନ୍ ଅଛି |", + "message.temporarily_down_description": "ଆମେ ଏହି ମୁହୂର୍ତ୍ତରେ ଉଚ୍ଚ ଉପଭୋକ୍ତା ଏହାକୁ ବ୍ୟବହାର କରୁଥିବା ର‌ ଅନୁଭବ କରୁଛୁ | ଦୟାକରି କିଛି ସମୟ ପରେ ଲଗଇନ୍ କରିବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ|", "error.fail_to_submit":"ମୂଲ୍ୟାୟନ ଦାଖଲ କରିବାରେ ବିଫଳ |", "error.fail_to_submit_review": "ସମୀକ୍ଷା ଦାଖଲ କରିବାରେ ବିଫଳ |", "error.sending_otp":"ଗୋଟିଏ ଥର ପାସୱାର୍ଡ ପଠାଇବାରେ ତ୍ରୁଟି |", diff --git a/apps/amakrushi/src/assets/icons/down-time.svg b/apps/amakrushi/src/assets/icons/down-time.svg new file mode 100644 index 00000000..e97a5634 --- /dev/null +++ b/apps/amakrushi/src/assets/icons/down-time.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/amakrushi/src/components/HomePage/index.module.css b/apps/amakrushi/src/components/HomePage/index.module.css index 8d0a256b..081b6dc1 100644 --- a/apps/amakrushi/src/components/HomePage/index.module.css +++ b/apps/amakrushi/src/components/HomePage/index.module.css @@ -73,6 +73,7 @@ color: white; font-family: 'Mulish-regular'; width: 26vw !important; + max-width: 100px !important; padding: 4px; border: none; border-radius: 40px !important; diff --git a/apps/amakrushi/src/components/HomePage/index.tsx b/apps/amakrushi/src/components/HomePage/index.tsx index 07dd6ffc..610583da 100644 --- a/apps/amakrushi/src/components/HomePage/index.tsx +++ b/apps/amakrushi/src/components/HomePage/index.tsx @@ -39,6 +39,8 @@ const HomePage: NextPage = () => { //@ts-ignore logEvent(analytics, 'Home_page'); + context?.fetchIsDown(); // check if server is down + if(!sessionStorage.getItem('conversationId')){ const newConversationId = uuidv4(); sessionStorage.setItem('conversationId', newConversationId); diff --git a/apps/amakrushi/src/components/NavBar/index.tsx b/apps/amakrushi/src/components/NavBar/index.tsx index f85cc700..77b372b0 100644 --- a/apps/amakrushi/src/components/NavBar/index.tsx +++ b/apps/amakrushi/src/components/NavBar/index.tsx @@ -49,7 +49,7 @@ function NavBar() { router.push('/'); }, [context, t]); - if (router.pathname === '/chat') { + if (router.pathname === '/chat' && !context?.isDown) { return (
diff --git a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx index 5d504305..24763e7b 100644 --- a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx +++ b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx @@ -1,7 +1,6 @@ import axios from 'axios'; //@ts-ignore import Chat from 'chatui'; -import { useRouter } from 'next/router'; import React, { ReactElement, useCallback, @@ -10,7 +9,6 @@ import React, { useMemo, useState, } from 'react'; -import { useCookies } from 'react-cookie'; import { analytics } from '../../../utils/firebase'; import { logEvent } from 'firebase/analytics'; import { AppContext } from '../../../context'; @@ -18,49 +16,55 @@ import { useLocalization } from '../../../hooks'; import { getMsgType } from '../../../utils/getMsgType'; import ChatMessageItem from '../../chat-message-item'; import { v4 as uuidv4 } from 'uuid'; -import toast from 'react-hot-toast'; +import DownTimePage from '../../down-time-page'; + const ChatUiWindow: React.FC = () => { - const t = useLocalization(); - const context = useContext(AppContext); - const router = useRouter(); - const [accessToken, setAccessToken] = useState(''); - const [cookies, setCookies] = useCookies(); + const context = useContext(AppContext); useEffect(() => { - !context?.loading && axios - .get( - `${process.env.NEXT_PUBLIC_BASE_URL - }/user/chathistory/${localStorage.getItem( - 'userID' - )}/${sessionStorage.getItem('conversationId')}` - ) - .then((res) => { - console.log('history:', res.data); - const normalizedChats = normalizedChat(res.data); - if(normalizedChats.length>0) context?.setMessages(normalizedChats); - }) - .catch((error) => { + const fetchData = async () => { + try { + await context?.fetchIsDown(); + if(context?.isDown){ + const chatHistory = await axios.get( + `${ + process.env.NEXT_PUBLIC_BASE_URL + }/user/chathistory/${localStorage.getItem( + 'userID' + )}/${sessionStorage.getItem('conversationId')}` + ); + console.log('history:', chatHistory.data); + const normalizedChats = normalizedChat(chatHistory.data); + if (normalizedChats.length > 0) { + context?.setMessages(normalizedChats); + } + } + } catch (error) { //@ts-ignore logEvent(analytics, 'console_error', { error_message: error.message, }); - }); - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [context?.setMessages]); + } + }; + !context?.loading && fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [context?.setMessages, context?.fetchIsDown]); const normalizedChat = (chats: any): any => { console.log('in normalized'); const conversationId = sessionStorage.getItem('conversationId'); - const history = chats.filter((item:any) => - conversationId === 'null' || item.conversationId === conversationId - ).flatMap((item:any) => [ + const history = chats + .filter( + (item: any) => + conversationId === 'null' || item.conversationId === conversationId + ) + .flatMap((item: any) => [ { text: item.query, position: 'right', repliedTimestamp: item.createdAt, - messageId: uuidv4() + messageId: uuidv4(), }, { text: item.response, @@ -68,7 +72,7 @@ const ChatUiWindow: React.FC = () => { sentTimestamp: item.createdAt, reaction: item.reaction, msgId: item.id, - messageId: item.id + messageId: item.id, }, ]); @@ -78,11 +82,9 @@ const ChatUiWindow: React.FC = () => { return history; }; - - const handleSend = useCallback( (type: string, val: any) => { - console.log('mssgs:', context?.messages) + console.log('mssgs:', context?.messages); if (type === 'text' && val.trim()) { context?.sendMessage(val.trim()); } @@ -115,29 +117,32 @@ const ChatUiWindow: React.FC = () => { console.log('debug:', { msgToRender }); const placeholder = useMemo(() => t('message.ask_ur_question'), [t]); - return ( -
- ( - - )} - onSend={handleSend} - locale="en-US" - placeholder={placeholder} - /> -
- ); + if (context?.isDown) { + return ; + } else + return ( +
+ ( + + )} + onSend={handleSend} + locale="en-US" + placeholder={placeholder} + /> +
+ ); }; export default ChatUiWindow; diff --git a/apps/amakrushi/src/components/chat-message-item/index.tsx b/apps/amakrushi/src/components/chat-message-item/index.tsx index 7fcf111e..071717bf 100644 --- a/apps/amakrushi/src/components/chat-message-item/index.tsx +++ b/apps/amakrushi/src/components/chat-message-item/index.tsx @@ -36,7 +36,7 @@ import { useFlags } from 'flagsmith/react'; const getToastMessage = (t: any, reaction: number): string => { if (reaction === 1) return t('toast.reaction_like'); - if (reaction === -1) return ''; + if (reaction === -1) return t('toast.reaction_dislike'); return t('toast.reaction_reset'); }; const ChatMessageItem: FC = ({ @@ -49,11 +49,10 @@ const ChatMessageItem: FC = ({ const context = useContext(AppContext); const [reaction, setReaction] = useState(message?.content?.data?.reaction); + useEffect(() => { setReaction(message?.content?.data?.reaction); - }, [message?.content?.data?.reaction]); - - + }, [message?.content?.data?.reaction]); const onLikeDislike = useCallback( ({ value, msgId }: { value: 0 | 1 | -1; msgId: string }) => { @@ -62,16 +61,7 @@ const ChatMessageItem: FC = ({ axios .get(url) .then((res: any) => { - if (value === -1) { - const dial = window?.confirm( - `Please call ${flags.dialer_number.value} to resolve your query with Ama Krushi Call centre` - ); - if (dial) { - const anchor = document.createElement('a'); - anchor.href = `tel:${flags.dialer_number.value}`; - anchor.click(); - } - } else toast.success(`${getToastMessage(t, value)}`); + toast.success(`${getToastMessage(t, value)}`); }) .catch((error: any) => { //@ts-ignore @@ -80,7 +70,7 @@ const ChatMessageItem: FC = ({ }); }); }, - [flags.dialer_number.value, t] + [t] ); const feedbackHandler = useCallback( diff --git a/apps/amakrushi/src/components/down-time-page/index.module.css b/apps/amakrushi/src/components/down-time-page/index.module.css new file mode 100644 index 00000000..4a96af22 --- /dev/null +++ b/apps/amakrushi/src/components/down-time-page/index.module.css @@ -0,0 +1,48 @@ +.container{ + background-color: var(--bg-color); + min-height: 100vh; + min-width: 100vw; + display: flex; + flex-direction: column; + align-items: center; +} + +.container span { + margin-top: 5vh; + margin-bottom: 1vh; + text-align: center; + font-family: Mulish-bold; + font-size: 2.6vh; + font-weight: 700; + color: var(--secondarygreen); +} + +.imageContainer { + margin-top: 15vh; + height: 15vh; + width: 15vh; +} + +.miniText { + text-align: center; + width: 80%; + color: var(--font); + font-size: 2vh; +} + +.backButton { + font-weight: 700 ; + font-size: 2vh !important; + color: white ; + margin: 4vh auto; + display: flex; + text-align: center; + justify-content: center; + align-items: center; + font-family: 'Mulish-regular'; + /* width: 12vh !important; */ + padding: 1vh 2vh; + border: none ; + border-radius: 40px !important; + background-color: var(--secondarygreen) !important; +} diff --git a/apps/amakrushi/src/components/down-time-page/index.tsx b/apps/amakrushi/src/components/down-time-page/index.tsx new file mode 100644 index 00000000..8c192b56 --- /dev/null +++ b/apps/amakrushi/src/components/down-time-page/index.tsx @@ -0,0 +1,30 @@ +'use client'; +import Menu from '../menu'; +import styles from './index.module.css'; +import Image from 'next/image'; +import downTimeIcon from '../../assets/icons/down-time.svg'; +import { useLocalization } from '../../hooks'; + +function DownTimePage() { + const t = useLocalization(); + return ( +
+
+ downTimeIcon +
+ {t("message.temporarily_down")} +

+ {t("message.temporarily_down_description")} +

+ + +
+ ); +} + +export default DownTimePage; \ No newline at end of file diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index e496e552..d4ecb18b 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -20,6 +20,8 @@ import toast from 'react-hot-toast'; import flagsmith from 'flagsmith/isomorphic'; import { io } from 'socket.io-client'; import { Button } from '@chakra-ui/react'; +import axios from 'axios'; +import { useFlags } from 'flagsmith/react'; function loadMessages(locale: string) { switch (locale) { @@ -41,7 +43,7 @@ const ContextProvider: FC<{ children: ReactElement; }> = ({ locale, children, localeMsgs, setLocale }) => { const t = useLocalization(); - + const flags = useFlags(['health_check_time']); const [users, setUsers] = useState([]); const [currentUser, setCurrentUser] = useState(); const [loading, setLoading] = useState(false); @@ -57,10 +59,11 @@ const ContextProvider: FC<{ ); const timer1 = flagsmith.getValue('timer1', { fallback: 5000 }); const timer2 = flagsmith.getValue('timer2', { fallback: 25000 }); + const [isDown, setIsDown] = useState(true); const [isConnected, setIsConnected] = useState(newSocket?.connected || false); console.log(messages); - + useEffect(() => { if ( (localStorage.getItem('phoneNumber') && localStorage.getItem('auth')) || @@ -97,7 +100,6 @@ const ContextProvider: FC<{ msg: { content: { title: string; choices: any }; messageId: string }; media: any; }) => { - if (msg.content.title !== '') { const newMsg = { username: user?.name, @@ -108,21 +110,23 @@ const ContextProvider: FC<{ botUuid: user?.id, reaction: 0, messageId: msg?.messageId, + //@ts-ignore + conversationId: msg?.content?.conversationId, sentTimestamp: Date.now(), ...media, }; - //@ts-ignore - if(conversationId===msg?.content?.conversationId) - setMessages((prev: any) => _.uniq([...prev, newMsg], ['messageId'])); - + + //@ts-ignore + if (conversationId === msg?.content?.conversationId) + setMessages((prev: any) => _.uniq([...prev, newMsg], ['messageId'])); } }, - [] + [conversationId] ); const onMessageReceived = useCallback( (msg: any): void => { - console.log('mssgs:',messages) + console.log('mssgs:', messages); console.log('#-debug:', { msg }); setLoading(false); setIsMsgReceiving(false); @@ -236,7 +240,7 @@ const ContextProvider: FC<{ //@ts-ignore const sendMessage = useCallback( (text: string, media: any, isVisibile = true): void => { - // console.log('mssgs:', messages) + // console.log('mssgs:', messages) setLoading(true); setIsMsgReceiving(true); @@ -261,7 +265,7 @@ const ContextProvider: FC<{ ); return; } - // console.log('mssgs:',messages) + // console.log('mssgs:',messages) send({ text, socketSession, socket: newSocket, conversationId }); if (isVisibile) if (media) { @@ -272,7 +276,7 @@ const ContextProvider: FC<{ } else { } } else { - //console.log('mssgs:',messages) + //console.log('mssgs:',messages) //@ts-ignore setMessages((prev: any) => [ ...prev.map((prevMsg: any) => ({ ...prevMsg, disabled: true })), @@ -288,19 +292,33 @@ const ContextProvider: FC<{ repliedTimestamp: Date.now(), }, ]); - // console.log('mssgs:',messages) + // console.log('mssgs:',messages) } }, - [ - t, - newSocket, - socketSession, - conversationId, - onSocketConnect, - currentUser?.id, - ] + [newSocket, socketSession, conversationId, t, onSocketConnect, currentUser?.id] ); + const fetchIsDown = useCallback(async () => { + try { + const res = await axios.get( + `${process.env.NEXT_PUBLIC_BASE_URL}/health/${flags?.health_check_time?.value}` + ); + const status = res.data.status; + console.log('hie', status); + if (status === 'OK') { + setIsDown(false); + } else { + setIsDown(true); + console.log('Server status is not OK'); + } + } catch (error) { + //@ts-ignore + logEvent(analytics, 'console_error', { + error_message: error.message, + }); + } + }, [setIsDown, flags]); + useEffect(() => { if (!socketSession && newSocket) { console.log('vbn:', { socketSession, newSocket }); @@ -315,6 +333,7 @@ const ContextProvider: FC<{ }); useEffect(() => { + if (isDown) return; let secondTimer: any; const timer = setTimeout(() => { if (isMsgReceiving && loading) { @@ -333,7 +352,7 @@ const ContextProvider: FC<{ clearTimeout(timer); clearTimeout(secondTimer); }; - }, [isMsgReceiving, loading, t, timer1, timer2]); + }, [isDown, isMsgReceiving, loading, t, timer1, timer2]); const values = useMemo( () => ({ @@ -356,6 +375,8 @@ const ContextProvider: FC<{ setConversationId, onSocketConnect, newSocket, + isDown, + fetchIsDown }), [ locale, @@ -376,6 +397,8 @@ const ContextProvider: FC<{ setConversationId, onSocketConnect, newSocket, + isDown, + fetchIsDown ] ); diff --git a/apps/amakrushi/src/pages/_app.tsx b/apps/amakrushi/src/pages/_app.tsx index e5c4959b..46da4648 100644 --- a/apps/amakrushi/src/pages/_app.tsx +++ b/apps/amakrushi/src/pages/_app.tsx @@ -36,7 +36,6 @@ const App = ({ pageProps, flagsmithState, }: AppProps & { flagsmithState: any }) => { - console.log("asdfg:",{flagsmithState}) const router = useRouter(); const { isAuthenticated, login } = useLogin(); const [launch, setLaunch] = useState(true); diff --git a/apps/amakrushi/src/pages/api/auth.js b/apps/amakrushi/src/pages/api/auth.js index 5e23ed21..1c90bf89 100644 --- a/apps/amakrushi/src/pages/api/auth.js +++ b/apps/amakrushi/src/pages/api/auth.js @@ -9,7 +9,7 @@ var client = jwksClient({ }); function getKey(header, callback) { client.getSigningKey(header.kid, function (err, key) { - var signingKey = key.publicKey || key.rsaPublicKey; + var signingKey = key?.publicKey || key?.rsaPublicKey; callback(null, signingKey); }); } From 091ed6ecdf6a1b664b639e2dc3d54e480c14ab44 Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Thu, 11 May 2023 22:46:55 +0530 Subject: [PATCH 07/25] Update ContextProvider.tsx (#118) --- apps/amakrushi/src/context/ContextProvider.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index d4ecb18b..3b4168ea 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -333,7 +333,6 @@ const ContextProvider: FC<{ }); useEffect(() => { - if (isDown) return; let secondTimer: any; const timer = setTimeout(() => { if (isMsgReceiving && loading) { @@ -352,7 +351,7 @@ const ContextProvider: FC<{ clearTimeout(timer); clearTimeout(secondTimer); }; - }, [isDown, isMsgReceiving, loading, t, timer1, timer2]); + }, [isMsgReceiving, loading, t, timer1, timer2]); const values = useMemo( () => ({ From 585157ecc3d27d9a963b37af4d00a0d9fa711868 Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Fri, 12 May 2023 13:40:13 +0530 Subject: [PATCH 08/25] Feat dialer popup (#120) * added down time page * Update chat.tsx --- apps/amakrushi/lang/en.json | 1 + apps/amakrushi/lang/or.json | 1 + apps/amakrushi/src/assets/icons/crossIcon.svg | 4 ++ .../amakrushi/src/components/NavBar/index.tsx | 2 +- .../PhoneView/ChatWindow/ChatUiWindow.tsx | 4 +- .../components/chat-message-item/index.tsx | 9 ++- .../components/dialer-popup/index.module.css | 59 +++++++++++++++++++ .../src/components/dialer-popup/index.tsx | 37 ++++++++++++ .../amakrushi/src/context/ContextProvider.tsx | 12 ++-- apps/amakrushi/src/pages/chat.tsx | 23 +++++++- 10 files changed, 140 insertions(+), 12 deletions(-) create mode 100644 apps/amakrushi/src/assets/icons/crossIcon.svg create mode 100644 apps/amakrushi/src/components/dialer-popup/index.module.css create mode 100644 apps/amakrushi/src/components/dialer-popup/index.tsx diff --git a/apps/amakrushi/lang/en.json b/apps/amakrushi/lang/en.json index e5aff6e6..c60eb4cb 100644 --- a/apps/amakrushi/lang/en.json +++ b/apps/amakrushi/lang/en.json @@ -57,6 +57,7 @@ "message.review_description": "Please write your experience's feedback.", "message.temporarily_down": "We're temporarily down", "message.temporarily_down_description": "We are experiencing high user volume at the moment, please try logging in after some time", + "message.dialer_popup":"You may speak to an Ama Krushi expert to get a satisfactory response", "error.fail_to_submit":"Failed to submit rating.", "error.fail_to_submit_review": "Failed to submit review.", "error.sending_otp":"Error sending OTP", diff --git a/apps/amakrushi/lang/or.json b/apps/amakrushi/lang/or.json index 7f424d3b..58c14be1 100644 --- a/apps/amakrushi/lang/or.json +++ b/apps/amakrushi/lang/or.json @@ -58,6 +58,7 @@ "message.review_description": "ଦୟାକରି ଆପଣଙ୍କର ଅଭିଜ୍ଞତା ମତାମତ ଲେଖନ୍ତୁ |", "message.temporarily_down": "କିଛି ସମୟ ପାଇଁ ସର୍ଭର ଡାଉନ୍ ଅଛି |", "message.temporarily_down_description": "ଆମେ ଏହି ମୁହୂର୍ତ୍ତରେ ଉଚ୍ଚ ଉପଭୋକ୍ତା ଏହାକୁ ବ୍ୟବହାର କରୁଥିବା ର‌ ଅନୁଭବ କରୁଛୁ | ଦୟାକରି କିଛି ସମୟ ପରେ ଲଗଇନ୍ କରିବାକୁ ଚେଷ୍ଟା କରନ୍ତୁ|", + "message.dialer_popup":"ଏକ ସନ୍ତୋଷଜନକ ପ୍ରତିକ୍ରିୟା ପାଇବା ପାଇଁ ଆପଣ ଆମା କ୍ରୁଶି ବିଶେଷଜ୍ଞଙ୍କ ସହିତ କଥା ହେଇପାରିବେ |", "error.fail_to_submit":"ମୂଲ୍ୟାୟନ ଦାଖଲ କରିବାରେ ବିଫଳ |", "error.fail_to_submit_review": "ସମୀକ୍ଷା ଦାଖଲ କରିବାରେ ବିଫଳ |", "error.sending_otp":"ଗୋଟିଏ ଥର ପାସୱାର୍ଡ ପଠାଇବାରେ ତ୍ରୁଟି |", diff --git a/apps/amakrushi/src/assets/icons/crossIcon.svg b/apps/amakrushi/src/assets/icons/crossIcon.svg new file mode 100644 index 00000000..066b7ef7 --- /dev/null +++ b/apps/amakrushi/src/assets/icons/crossIcon.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/apps/amakrushi/src/components/NavBar/index.tsx b/apps/amakrushi/src/components/NavBar/index.tsx index 77b372b0..1fa43079 100644 --- a/apps/amakrushi/src/components/NavBar/index.tsx +++ b/apps/amakrushi/src/components/NavBar/index.tsx @@ -17,7 +17,7 @@ import toast from 'react-hot-toast'; function NavBar() { const flags = useFlags(['show_download_button', 'show_share_button']); - const defaultLang = flagsmith.getValue('default_lang', { fallback: 'en' }); + const defaultLang = flagsmith.getValue('default_lang', { fallback: 'or' }); const [isEngActive, setIsEngActive] = useState( localStorage.getItem('locale') ? localStorage.getItem('locale') === 'en' diff --git a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx index 24763e7b..3b8abd60 100644 --- a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx +++ b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx @@ -26,7 +26,7 @@ const ChatUiWindow: React.FC = () => { const fetchData = async () => { try { await context?.fetchIsDown(); - if(context?.isDown){ + if(!context?.isDown){ const chatHistory = await axios.get( `${ process.env.NEXT_PUBLIC_BASE_URL @@ -48,7 +48,7 @@ const ChatUiWindow: React.FC = () => { } }; !context?.loading && fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [context?.setMessages, context?.fetchIsDown]); const normalizedChat = (chats: any): any => { diff --git a/apps/amakrushi/src/components/chat-message-item/index.tsx b/apps/amakrushi/src/components/chat-message-item/index.tsx index 071717bf..e98ae5fb 100644 --- a/apps/amakrushi/src/components/chat-message-item/index.tsx +++ b/apps/amakrushi/src/components/chat-message-item/index.tsx @@ -36,7 +36,6 @@ import { useFlags } from 'flagsmith/react'; const getToastMessage = (t: any, reaction: number): string => { if (reaction === 1) return t('toast.reaction_like'); - if (reaction === -1) return t('toast.reaction_dislike'); return t('toast.reaction_reset'); }; const ChatMessageItem: FC = ({ @@ -61,7 +60,11 @@ const ChatMessageItem: FC = ({ axios .get(url) .then((res: any) => { - toast.success(`${getToastMessage(t, value)}`); + if (value === -1) { + context?.setShowDialerPopup(true); + } else { + toast.success(`${getToastMessage(t, value)}`); + } }) .catch((error: any) => { //@ts-ignore @@ -70,6 +73,7 @@ const ChatMessageItem: FC = ({ }); }); }, + // eslint-disable-next-line react-hooks/exhaustive-deps [t] ); @@ -147,6 +151,7 @@ const ChatMessageItem: FC = ({ display: 'flex', flexDirection: 'column', position: 'relative', + maxWidth: '90vw' }}>
= ({ setShowDialerPopup }) => { + const flags = useFlags(['dialer_number']); + const t = useLocalization(); + + return ( + + ); +}; + +export default DialerPopup; diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index 3b4168ea..d58def70 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -60,7 +60,7 @@ const ContextProvider: FC<{ const timer1 = flagsmith.getValue('timer1', { fallback: 5000 }); const timer2 = flagsmith.getValue('timer2', { fallback: 25000 }); const [isDown, setIsDown] = useState(true); - + const [showDialerPopup, setShowDialerPopup] = useState(false); const [isConnected, setIsConnected] = useState(newSocket?.connected || false); console.log(messages); @@ -375,7 +375,9 @@ const ContextProvider: FC<{ onSocketConnect, newSocket, isDown, - fetchIsDown + fetchIsDown, + showDialerPopup, + setShowDialerPopup }), [ locale, @@ -397,7 +399,9 @@ const ContextProvider: FC<{ onSocketConnect, newSocket, isDown, - fetchIsDown + fetchIsDown, + showDialerPopup, + setShowDialerPopup ] ); @@ -412,7 +416,7 @@ const ContextProvider: FC<{ }; const SSR: FC<{ children: ReactElement }> = ({ children }) => { - const defaultLang = flagsmith.getValue('default_lang', { fallback: 'en' }); + const defaultLang = flagsmith.getValue('default_lang', { fallback: 'or' }); const [locale, setLocale] = useState( localStorage.getItem('locale') || defaultLang ); diff --git a/apps/amakrushi/src/pages/chat.tsx b/apps/amakrushi/src/pages/chat.tsx index 73374cd9..34f5cfc7 100644 --- a/apps/amakrushi/src/pages/chat.tsx +++ b/apps/amakrushi/src/pages/chat.tsx @@ -3,6 +3,10 @@ import Head from "next/head"; import dynamic from "next/dynamic"; import { useLocalization } from "../hooks/useLocalization"; import Menu from "../components/menu"; +import { useContext } from "react"; +import { AppContext } from "../context"; +import styles from "../components/dialer-popup/index.module.css"; +import DialerPopUp from "../components/dialer-popup"; const ChatUiWindow = dynamic( () => import("../components/PhoneView/ChatWindow/ChatUiWindow"), @@ -11,21 +15,34 @@ const ChatUiWindow = dynamic( const Chat: NextPage = () => { const t = useLocalization(); + const context = useContext(AppContext); return ( <> {t("label.title")} - + {context?.showDialerPopup && ( +
context?.setShowDialerPopup(false)} + > + {/* Only render the DialerPopup component when showDialerPopup is true */} + {context?.showDialerPopup && + + } +
+)} +
+ }}>
From ad9f44b60b26d790c8cfc0bd36295ea5b5d1c368 Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Fri, 12 May 2023 19:18:08 +0530 Subject: [PATCH 09/25] Added Auth header (#122) * added down time page * added dialer popup * added auth in headers * Update chat.tsx --- .../src/components/HistoryPage/index.tsx | 10 +- .../src/components/MorePage/FAQPage/index.tsx | 12 +- .../MorePage/FeedbackPage/index.tsx | 146 ++++++++++++------ .../PhoneView/ChatWindow/ChatUiWindow.tsx | 13 +- .../src/components/chat-item/index.tsx | 11 +- .../components/chat-message-item/index.tsx | 8 +- 6 files changed, 130 insertions(+), 70 deletions(-) diff --git a/apps/amakrushi/src/components/HistoryPage/index.tsx b/apps/amakrushi/src/components/HistoryPage/index.tsx index 37ba6126..419216e3 100644 --- a/apps/amakrushi/src/components/HistoryPage/index.tsx +++ b/apps/amakrushi/src/components/HistoryPage/index.tsx @@ -25,11 +25,11 @@ const HistoryPage: NextPage = () => { logEvent(analytics, 'Chat_History_page'); axios - .get( - `${ - process.env.NEXT_PUBLIC_BASE_URL - }/user/conversations/${localStorage.getItem('userID')}` - ) + .get(`${process.env.NEXT_PUBLIC_BASE_URL}/user/conversations`, { + headers: { + authorization: `Bearer ${localStorage.getItem('auth')}`, + }, + }) .then((res) => { const sortedConversations = _.filter( res?.data, diff --git a/apps/amakrushi/src/components/MorePage/FAQPage/index.tsx b/apps/amakrushi/src/components/MorePage/FAQPage/index.tsx index 848d5977..868f9728 100644 --- a/apps/amakrushi/src/components/MorePage/FAQPage/index.tsx +++ b/apps/amakrushi/src/components/MorePage/FAQPage/index.tsx @@ -43,7 +43,12 @@ const FAQPage: React.FC = () => { while (true) { try { const response = await axios.get( - `${process.env.NEXT_PUBLIC_BASE_URL}/faq?page=${page}` + `${process.env.NEXT_PUBLIC_BASE_URL}/faq?page=${page}`, + { + headers: { + authorization: `Bearer ${localStorage.getItem('auth')}`, + }, + } ); const newData = response.data.faqs; @@ -117,6 +122,7 @@ const FAQPage: React.FC = () => { */} + {/* @ts-ignore */} {faqData.map((faq, idx) => ( @@ -158,7 +164,9 @@ const FAQPage: React.FC = () => {
{t('message.dial_description')}
- +
callIcon
diff --git a/apps/amakrushi/src/components/MorePage/FeedbackPage/index.tsx b/apps/amakrushi/src/components/MorePage/FeedbackPage/index.tsx index 45b0fd2b..c2fe7d40 100644 --- a/apps/amakrushi/src/components/MorePage/FeedbackPage/index.tsx +++ b/apps/amakrushi/src/components/MorePage/FeedbackPage/index.tsx @@ -2,7 +2,13 @@ import starIcon from '../../../assets/icons/star.svg'; import starOutlineIcon from '../../../assets/icons/star-outline.svg'; import Image from 'next/image'; import styles from './index.module.css'; -import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'; +import React, { + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from 'react'; import Menu from '../../menu'; //@ts-ignore import { analytics } from '../../../utils/firebase'; @@ -16,7 +22,6 @@ import { useLocalization } from '../../../hooks'; const FeedbackPage: React.FC = () => { const t = useLocalization(); - console.log("vbn aab bbb") const context = useContext(AppContext); const [rating, setRating] = useState(1); const [review, setReview] = useState(''); @@ -26,50 +31,79 @@ const FeedbackPage: React.FC = () => { logEvent(analytics, 'Feedback_page'); }, []); - const [submitError,ratingSubmitted,reviewSubmitted,reviewSubmitError] =useMemo(()=>[t('error.fail_to_submit'),t('message.rating_submitted'),t('message.review_submitted'),t('error.fail_to_submit_review')],[t]); - const [feedback,ratingLabel] =useMemo(()=>[t("label.feedback"),t("message.rating")],[t]); - - const submitReview = useCallback((r: number | string) => { - - if (typeof r === "number") { - axios.post(`${process.env.NEXT_PUBLIC_BASE_URL}/feedback`, { - rating: r, - phoneNumber: localStorage.getItem('phoneNumber'), - userId: localStorage.getItem('userID'), - }) - .then(response => { - toast.success(ratingSubmitted); - }) - .catch(error => { - toast.error(submitError); - //@ts-ignore - logEvent(analytics, 'console_error', { - error_message: error.message, - }); - }); - } else if (typeof r === "string") { - axios.post(`${process.env.NEXT_PUBLIC_BASE_URL}/feedback`, { - review: r, - phoneNumber: localStorage.getItem('phoneNumber'), - userId: localStorage.getItem('userID'), - }) - .then(response => { - toast.success(reviewSubmitted) - }) - .catch(error => { - toast.error(reviewSubmitError); - //@ts-ignore - logEvent(analytics, 'console_error', { - error_message: error.message, - }); - }); - } - }, [ratingSubmitted, reviewSubmitError, reviewSubmitted, submitError]); + const [submitError, ratingSubmitted, reviewSubmitted, reviewSubmitError] = + useMemo( + () => [ + t('error.fail_to_submit'), + t('message.rating_submitted'), + t('message.review_submitted'), + t('error.fail_to_submit_review'), + ], + [t] + ); + const [feedback, ratingLabel] = useMemo( + () => [t('label.feedback'), t('message.rating')], + [t] + ); + const submitReview = useCallback( + (r: number | string) => { + if (typeof r === 'number') { + axios + .post( + `${process.env.NEXT_PUBLIC_BASE_URL}/feedback`, + { + rating: r, + phoneNumber: localStorage.getItem('phoneNumber'), + }, + { + headers: { + authorization: `Bearer ${localStorage.getItem('auth')}`, + }, + } + ) + .then((response) => { + toast.success(ratingSubmitted); + }) + .catch((error) => { + toast.error(submitError); + //@ts-ignore + logEvent(analytics, 'console_error', { + error_message: error.message, + }); + }); + } else if (typeof r === 'string') { + axios + .post( + `${process.env.NEXT_PUBLIC_BASE_URL}/feedback`, + { + review: r, + phoneNumber: localStorage.getItem('phoneNumber'), + }, + { + headers: { + authorization: `Bearer ${localStorage.getItem('auth')}`, + }, + } + ) + .then((response) => { + toast.success(reviewSubmitted); + }) + .catch((error) => { + toast.error(reviewSubmitError); + //@ts-ignore + logEvent(analytics, 'console_error', { + error_message: error.message, + }); + }); + } + }, + [ratingSubmitted, reviewSubmitError, reviewSubmitted, submitError] + ); if (!flags?.show_feedback_page?.enabled) { return ; - } else + } else return ( <>
@@ -80,16 +114,22 @@ const FeedbackPage: React.FC = () => { {Array.from({ length: 5 }, (_, index) => { if (index + 1 <= rating) { return ( -
setRating(index + 1)} key={index} className={styles.star}> - +
setRating(index + 1)} + key={index} + className={styles.star}> + starIcon
); } else { return ( -
setRating(index + 1)} key={index} className={styles.star}> +
setRating(index + 1)} + key={index} + className={styles.star}> @@ -98,11 +138,13 @@ const FeedbackPage: React.FC = () => { } })}
-

{t("message.rating_description")}

- +

{t('message.rating_description')}

+
-

{t("message.review")}

+

{t('message.review')}

- - + +
diff --git a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx index 3b8abd60..236c96b4 100644 --- a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx +++ b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx @@ -30,9 +30,12 @@ const ChatUiWindow: React.FC = () => { const chatHistory = await axios.get( `${ process.env.NEXT_PUBLIC_BASE_URL - }/user/chathistory/${localStorage.getItem( - 'userID' - )}/${sessionStorage.getItem('conversationId')}` + }/user/chathistory/${sessionStorage.getItem('conversationId')}`, + { + headers: { + authorization: `Bearer ${localStorage.getItem('auth')}`, + }, + } ); console.log('history:', chatHistory.data); const normalizedChats = normalizedChat(chatHistory.data); @@ -40,7 +43,7 @@ const ChatUiWindow: React.FC = () => { context?.setMessages(normalizedChats); } } - } catch (error) { + } catch (error:any) { //@ts-ignore logEvent(analytics, 'console_error', { error_message: error.message, @@ -48,7 +51,7 @@ const ChatUiWindow: React.FC = () => { } }; !context?.loading && fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps + // eslint-disable-next-line react-hooks/exhaustive-deps }, [context?.setMessages, context?.fetchIsDown]); const normalizedChat = (chats: any): any => { diff --git a/apps/amakrushi/src/components/chat-item/index.tsx b/apps/amakrushi/src/components/chat-item/index.tsx index 8fe7feca..c5f872ec 100644 --- a/apps/amakrushi/src/components/chat-item/index.tsx +++ b/apps/amakrushi/src/components/chat-item/index.tsx @@ -32,11 +32,12 @@ const ChatItem: React.FC = ({ if (confirmed) { axios .get( - `${ - process.env.NEXT_PUBLIC_BASE_URL - }/user/conversations/delete/${localStorage.getItem( - 'userID' - )}/${conversationId}` + `${process.env.NEXT_PUBLIC_BASE_URL}/user/conversations/delete/${conversationId}`, + { + headers: { + authorization: `Bearer ${localStorage.getItem('auth')}`, + }, + } ) .then((res) => { console.log('deleting conversation'); diff --git a/apps/amakrushi/src/components/chat-message-item/index.tsx b/apps/amakrushi/src/components/chat-message-item/index.tsx index fcfcae30..65974b89 100644 --- a/apps/amakrushi/src/components/chat-message-item/index.tsx +++ b/apps/amakrushi/src/components/chat-message-item/index.tsx @@ -58,7 +58,11 @@ const ChatMessageItem: FC = ({ let url = getReactionUrl({ msgId, reaction: value }); axios - .get(url) + .get(url, { + headers: { + authorization: `Bearer ${localStorage.getItem('auth')}`, + }, + }) .then((res: any) => { if (value === -1) { context?.setShowDialerPopup(true); @@ -151,7 +155,7 @@ const ChatMessageItem: FC = ({ display: 'flex', flexDirection: 'column', position: 'relative', - maxWidth: '90vw' + maxWidth: '90vw', }}>
Date: Tue, 16 May 2023 16:51:52 +0530 Subject: [PATCH 10/25] chore: msgId display for testing (#127) * chore: msgId display for testing --- .../components/chat-message-item/index.tsx | 49 ++++++++++++++++--- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/apps/amakrushi/src/components/chat-message-item/index.tsx b/apps/amakrushi/src/components/chat-message-item/index.tsx index 991f6640..5fb9e725 100644 --- a/apps/amakrushi/src/components/chat-message-item/index.tsx +++ b/apps/amakrushi/src/components/chat-message-item/index.tsx @@ -18,13 +18,14 @@ import React, { useEffect, useState, } from 'react'; -import { Button } from 'react-bootstrap'; + import { toast } from 'react-hot-toast'; import styles from './index.module.css'; import { analytics } from '../../utils/firebase'; import { logEvent } from 'firebase/analytics'; import RightIcon from '../../assets/icons/right.jsx'; +import CopyText from '../../assets/icons/copy-text.svg'; import MsgThumbsUp from '../../assets/icons/msg-thumbs-up.jsx'; import MsgThumbsDown from '../../assets/icons/msg-thumbs-down.jsx'; import { AppContext } from '../../context'; @@ -33,6 +34,9 @@ import { getFormatedTime } from '../../utils/getUtcTime'; import { useLocalization } from '../../hooks/useLocalization'; import { getReactionUrl } from '../../utils/getUrls'; import { useFlags } from 'flagsmith/react'; +import Image from 'next/image'; +import { Button } from '@chakra-ui/react'; +import flagsmith from 'flagsmith/isomorphic'; const getToastMessage = (t: any, reaction: number): string => { if (reaction === 1) return t('toast.reaction_like'); @@ -43,7 +47,8 @@ const ChatMessageItem: FC = ({ message, onSend, }) => { - const flags = useFlags(['dialer_number']); + const flags = useFlags(['show_msg_id']); + const t = useLocalization(); const context = useContext(AppContext); const [reaction, setReaction] = useState(message?.content?.data?.reaction); @@ -81,6 +86,15 @@ const ChatMessageItem: FC = ({ [t] ); + + async function copyTextToClipboard(text: string) { + console.log("here") + if ('clipboard' in navigator) { + return await navigator.clipboard.writeText(text); + } else { + return document.execCommand('copy', true, text); + } + } const feedbackHandler = useCallback( ({ like, msgId }: { like: 0 | 1 | -1; msgId: string }) => { console.log('vbnm:', { reaction, like }); @@ -173,12 +187,28 @@ const ChatMessageItem: FC = ({ content?.data?.position === 'right' ? 'white' : 'var(--font)', }}> {content.text} +
+ + {content?.data?.position === "left" && flags?.show_msg_id?.enabled &&( + + + + ) + } + = ({ }}> {getFormatedTime( content?.data?.sentTimestamp || - content?.data?.repliedTimestamp + content?.data?.repliedTimestamp )} +
{content?.data?.position === 'left' && ( @@ -255,7 +286,7 @@ const ChatMessageItem: FC = ({ {getFormatedTime( content?.data?.sentTimestamp || - content?.data?.repliedTimestamp + content?.data?.repliedTimestamp )}
@@ -289,7 +320,7 @@ const ChatMessageItem: FC = ({ {getFormatedTime( content?.data?.sentTimestamp || - content?.data?.repliedTimestamp + content?.data?.repliedTimestamp )}
@@ -327,7 +358,7 @@ const ChatMessageItem: FC = ({ {getFormatedTime( content?.data?.sentTimestamp || - content?.data?.repliedTimestamp + content?.data?.repliedTimestamp )}
@@ -369,4 +400,6 @@ const ChatMessageItem: FC = ({ } }; -export default ChatMessageItem; \ No newline at end of file +export default ChatMessageItem; + + \ No newline at end of file From ecfa55c8201257b71093b82592288dee86b28c8a Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Tue, 16 May 2023 17:07:17 +0530 Subject: [PATCH 11/25] Feat dsply msg (#128) * fix: history not loading on refresh --- .../src/components/PhoneView/ChatWindow/ChatUiWindow.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx index c8ef749e..5e43a79d 100644 --- a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx +++ b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx @@ -27,6 +27,7 @@ const ChatUiWindow: React.FC = () => { try { await context?.fetchIsDown(); if(!context?.isDown){ + const chatHistory = await axios.get( `${ process.env.NEXT_PUBLIC_BASE_URL @@ -37,6 +38,7 @@ const ChatUiWindow: React.FC = () => { }, } ); + console.log("ghji:",chatHistory) console.log('history:', chatHistory.data); const normalizedChats = normalizedChat(chatHistory.data); if (normalizedChats.length > 0) { @@ -51,8 +53,9 @@ const ChatUiWindow: React.FC = () => { } }; !context?.loading && fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [context?.setMessages, context?.fetchIsDown]); + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [context?.setMessages, context?.fetchIsDown,context?.loading,context?.isDown]); const normalizedChat = (chats: any): any => { console.log('in normalized'); From 129d6eb6e1aeda06d54c445ce9531648a784048a Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Tue, 23 May 2023 14:13:25 +0530 Subject: [PATCH 12/25] chore: fixed userID bug (#130) --- apps/amakrushi/src/components/OTPpage/index.tsx | 7 +++++++ apps/amakrushi/src/context/ContextProvider.tsx | 11 +++++++++-- apps/amakrushi/src/pages/_app.tsx | 8 ++++---- apps/amakrushi/src/pages/index.tsx | 2 +- yarn.lock | 10 +++++----- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/apps/amakrushi/src/components/OTPpage/index.tsx b/apps/amakrushi/src/components/OTPpage/index.tsx index 37476c6c..51ad0abf 100644 --- a/apps/amakrushi/src/components/OTPpage/index.tsx +++ b/apps/amakrushi/src/components/OTPpage/index.tsx @@ -26,6 +26,13 @@ const OTPpage: React.FC = () => { const [countdownIntervalId, setCountdownIntervalId] = useState(null); console.log("vbn:", { context }); + useEffect(() => { + if(!router.query.state || router.query.state?.length !== 10){ + router.push('/login') + } + }, [router]) + + const handleOTPSubmit: React.FormEventHandler = async ( event: React.FormEvent ) => { diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index 78bb7235..a6fb6632 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -22,6 +22,7 @@ import { io } from 'socket.io-client'; import { Button } from '@chakra-ui/react'; import axios from 'axios'; import { useFlags } from 'flagsmith/react'; +import { useCookies } from 'react-cookie'; function loadMessages(locale: string) { switch (locale) { @@ -55,18 +56,19 @@ const ContextProvider: FC<{ sessionStorage.getItem('conversationId') ); const [isMobileAvailable, setIsMobileAvailable] = useState( - localStorage.getItem('phoneNumber') ? true : false || false + localStorage.getItem('userID') ? true : false || false ); const timer1 = flagsmith.getValue('timer1', { fallback: 5000 }); const timer2 = flagsmith.getValue('timer2', { fallback: 25000 }); const [isDown, setIsDown] = useState(true); const [showDialerPopup, setShowDialerPopup] = useState(false); const [isConnected, setIsConnected] = useState(newSocket?.connected || false); + const [cookie, setCookie, removeCookie] = useCookies(); console.log(messages); useEffect(() => { if ( - (localStorage.getItem('phoneNumber') && localStorage.getItem('auth')) || + (localStorage.getItem('userID') && localStorage.getItem('auth')) || isMobileAvailable ) { setNewSocket( @@ -240,6 +242,11 @@ const ContextProvider: FC<{ //@ts-ignore const sendMessage = useCallback( (text: string, media: any, isVisibile = true): void => { + if(!localStorage.getItem('userID') || !sessionStorage.getItem('conversationId')){ + removeCookie('access_token', { path: '/' }); + location?.reload(); + return; + } // console.log('mssgs:', messages) setLoading(true); setIsMsgReceiving(true); diff --git a/apps/amakrushi/src/pages/_app.tsx b/apps/amakrushi/src/pages/_app.tsx index e5c4959b..acccf83b 100644 --- a/apps/amakrushi/src/pages/_app.tsx +++ b/apps/amakrushi/src/pages/_app.tsx @@ -36,7 +36,6 @@ const App = ({ pageProps, flagsmithState, }: AppProps & { flagsmithState: any }) => { - console.log("asdfg:",{flagsmithState}) const router = useRouter(); const { isAuthenticated, login } = useLogin(); const [launch, setLaunch] = useState(true); @@ -50,18 +49,19 @@ const App = ({ const handleLoginRedirect = useCallback(() => { if (router.pathname === "/login" || router.pathname.startsWith("/otp")) { // already logged in then send to home - if (cookie["access_token"] !== undefined && localStorage.getItem('phoneNumber')) { + if (cookie["access_token"] !== undefined && localStorage.getItem('userID')) { router.push("/"); } } else { // not logged in then send to login page - if (cookie["access_token"] === undefined || !localStorage.getItem('phoneNumber')) { + if (cookie["access_token"] === undefined || !localStorage.getItem('userID')) { + removeCookie('access_token', { path: '/' }); localStorage.clear(); sessionStorage.clear(); router.push("/login"); } } - }, [cookie, router]); + }, [cookie, removeCookie, router]); useEffect(() => { handleLoginRedirect(); diff --git a/apps/amakrushi/src/pages/index.tsx b/apps/amakrushi/src/pages/index.tsx index 92e4ac70..bf0fa003 100644 --- a/apps/amakrushi/src/pages/index.tsx +++ b/apps/amakrushi/src/pages/index.tsx @@ -11,7 +11,7 @@ const Home: NextPage = () => { const t = useLocalization(); const context = useContext(AppContext); useEffect(() => { - if (localStorage.getItem("phoneNumber")) { + if (localStorage.getItem("userID")) { context?.setIsMobileAvailable(true); } }, [context?.setIsMobileAvailable]); diff --git a/yarn.lock b/yarn.lock index 829468dd..04524d00 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6091,7 +6091,7 @@ "require-from-string" "^2.0.2" "uri-js" "^4.2.2" -"amakrushi-uci@file:C:\\Users\\prtkj\\Desktop\\app\\apps\\amakrushi": +"amakrushi-uci@file:D:\\STUDIES\\app\\apps\\amakrushi": "resolved" "file:apps/amakrushi" "version" "0.1.0" dependencies: @@ -7273,7 +7273,7 @@ "resolved" "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz" "version" "0.7.0" -"chatui@*", "chatui@file:C:\\Users\\prtkj\\Desktop\\app\\packages\\chat-ui": +"chatui@*", "chatui@file:D:\\STUDIES\\app\\packages\\chat-ui": "resolved" "file:packages/chat-ui" "version" "0.0.0" dependencies: @@ -8500,7 +8500,7 @@ dependencies: "@leichtgewicht/ip-codec" "^2.0.1" -"docs@file:C:\\Users\\prtkj\\Desktop\\app\\apps\\docs": +"docs@file:D:\\STUDIES\\app\\apps\\docs": "resolved" "file:apps/docs" "version" "0.0.0" dependencies: @@ -8907,7 +8907,7 @@ "object.assign" "^4.1.2" "object.entries" "^1.1.5" -"eslint-config-custom@*", "eslint-config-custom@file:C:\\Users\\prtkj\\Desktop\\app\\packages\\eslint-config-custom": +"eslint-config-custom@*", "eslint-config-custom@file:D:\\STUDIES\\app\\packages\\eslint-config-custom": "resolved" "file:packages/eslint-config-custom" "version" "0.0.0" dependencies: @@ -18108,7 +18108,7 @@ "minimist" "^1.2.6" "strip-bom" "^3.0.0" -"tsconfig@*", "tsconfig@file:C:\\Users\\prtkj\\Desktop\\app\\packages\\tsconfig": +"tsconfig@*", "tsconfig@file:D:\\STUDIES\\app\\packages\\tsconfig": "resolved" "file:packages/tsconfig" "version" "0.0.0" From 4af2c3194092c76ec2c1ca53f29a1f3c76e8a7cb Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Tue, 23 May 2023 14:20:00 +0530 Subject: [PATCH 13/25] Feat fcm (#133) * feat: added fcm --------- Co-authored-by: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> --- .../amakrushi/public/firebase-messaging-sw.js | 37 +++ .../amakrushi/src/context/ContextProvider.tsx | 3 +- apps/amakrushi/src/hooks/useLogin.ts | 6 + apps/amakrushi/src/pages/_app.tsx | 74 ++++- apps/amakrushi/src/pages/api/getUser.js | 23 ++ apps/amakrushi/src/pages/api/updateUser.js | 32 +++ apps/amakrushi/src/utils/FcmNotification.tsx | 34 +++ apps/amakrushi/src/utils/firebase.ts | 8 + apps/amakrushi/src/utils/serviceWorker.ts | 262 +++++++++--------- apps/amakrushi/tsconfig.json | 2 +- turbo.json | 6 +- 11 files changed, 344 insertions(+), 143 deletions(-) create mode 100644 apps/amakrushi/public/firebase-messaging-sw.js create mode 100644 apps/amakrushi/src/pages/api/getUser.js create mode 100644 apps/amakrushi/src/pages/api/updateUser.js create mode 100644 apps/amakrushi/src/utils/FcmNotification.tsx diff --git a/apps/amakrushi/public/firebase-messaging-sw.js b/apps/amakrushi/public/firebase-messaging-sw.js new file mode 100644 index 00000000..a809f55b --- /dev/null +++ b/apps/amakrushi/public/firebase-messaging-sw.js @@ -0,0 +1,37 @@ +importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js'); +importScripts( + 'https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js' +); + +// Set Firebase configuration, once available +self.addEventListener('fetch', () => { + const urlParams = new URLSearchParams(location.search); + self.firebaseConfig = Object.fromEntries(urlParams); +}); + +// "Default" Firebase configuration (prevents errors) +const defaultConfig = { + apiKey: true, + projectId: true, + messagingSenderId: true, + appId: true, +}; + +// Initialize Firebase app +firebase.initializeApp(self.firebaseConfig || defaultConfig); +const messaging = firebase.messaging(); + +messaging.onBackgroundMessage((payload) => { + console.log('Received background message ', payload); + const notificationTitle = payload.notification.title; + const notificationOptions = { + body: payload.notification.body, + icon: payload.notification.image, + tag: 'notification', + vibrate: [200, 100, 200], + renotify: true, + }; + + self.registration.showNotification(notificationTitle, notificationOptions); +}); + diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index a6fb6632..2a3e0955 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -350,6 +350,7 @@ const ContextProvider: FC<{ toast.error(`${t('message.retry')}`); setIsMsgReceiving(false); setLoading(false); + fetchIsDown(); } }, timer2); } @@ -359,7 +360,7 @@ const ContextProvider: FC<{ clearTimeout(timer); clearTimeout(secondTimer); }; - }, [isDown, isMsgReceiving, loading, t, timer1, timer2]); + }, [fetchIsDown, isDown, isMsgReceiving, loading, t, timer1, timer2]); const values = useMemo( () => ({ diff --git a/apps/amakrushi/src/hooks/useLogin.ts b/apps/amakrushi/src/hooks/useLogin.ts index 72d59d86..4b70587d 100644 --- a/apps/amakrushi/src/hooks/useLogin.ts +++ b/apps/amakrushi/src/hooks/useLogin.ts @@ -33,6 +33,9 @@ export const useLogin = () => { .then((response) => { if (response.data === null) { toast.error('Invalid Access Token'); + removeCookie('access_token', { path: '/' }); + localStorage.clear(); + sessionStorage.clear(); router.push('/login'); console.log('response null'); } else { @@ -45,6 +48,9 @@ export const useLogin = () => { logEvent(analytics, 'console_error', { error_message: err.message, }); + removeCookie('access_token', { path: '/' }); + localStorage.clear(); + sessionStorage.clear(); router.push('/login'); console.log('catch err'); }); diff --git a/apps/amakrushi/src/pages/_app.tsx b/apps/amakrushi/src/pages/_app.tsx index acccf83b..25bdf475 100644 --- a/apps/amakrushi/src/pages/_app.tsx +++ b/apps/amakrushi/src/pages/_app.tsx @@ -15,7 +15,9 @@ import { FlagsmithProvider } from 'flagsmith/react'; import { useLogin } from '../hooks'; import axios from 'axios'; - +import { messaging } from '../utils/firebase'; +import { getToken } from 'firebase/messaging'; +import FcmNotification from '../utils/FcmNotification'; const LaunchPage = dynamic(() => import('../components/LaunchPage'), { ssr: false, @@ -26,7 +28,7 @@ const NavBar = dynamic(() => import('../components/NavBar'), { function SafeHydrate({ children }: { children: ReactElement }) { return (
- {typeof window === "undefined" ? null : children} + {typeof window === 'undefined' ? null : children}
); } @@ -40,6 +42,7 @@ const App = ({ const { isAuthenticated, login } = useLogin(); const [launch, setLaunch] = useState(true); const [cookie, setCookie, removeCookie] = useCookies(); + useEffect(() => { setTimeout(() => { setLaunch(false); @@ -47,18 +50,25 @@ const App = ({ }, []); const handleLoginRedirect = useCallback(() => { - if (router.pathname === "/login" || router.pathname.startsWith("/otp")) { + if (router.pathname === '/login' || router.pathname.startsWith('/otp')) { // already logged in then send to home - if (cookie["access_token"] !== undefined && localStorage.getItem('userID')) { - router.push("/"); + + if ( + cookie['access_token'] && + localStorage.getItem('userID') + ) { + router.push('/'); } } else { // not logged in then send to login page - if (cookie["access_token"] === undefined || !localStorage.getItem('userID')) { - removeCookie('access_token', { path: '/' }); + if ( + !cookie['access_token'] || + !localStorage.getItem('userID') + ) { + localStorage.clear(); sessionStorage.clear(); - router.push("/login"); + router.push('/login'); } } }, [cookie, removeCookie, router]); @@ -67,13 +77,49 @@ const App = ({ handleLoginRedirect(); }, [handleLoginRedirect]); + useEffect(() => { + if (!isAuthenticated) { + login(); + } + }, [isAuthenticated, login]); useEffect(() => { - if(!isAuthenticated){ - login(); + if (!isAuthenticated || !localStorage.getItem('userID')) return; + // Request user for notification permission + const requestPermission = async () => { + const permission = await Notification.requestPermission(); + if (permission === 'granted') { + // Get token + const token = await getToken(messaging, { + vapidKey: process.env.NEXT_PUBLIC_FCM_VAPID_KEY, + }); + localStorage.setItem('fcm-token', token); + console.log('Token', token); } - }, [isAuthenticated, login]); + }; + const updateUser = async () => { + try { + const userID = localStorage.getItem('userID'); + const user = await axios.get(`/api/getUser?userID=${userID}`); + const fcmToken = localStorage.getItem('fcm-token'); + if ( + fcmToken && + user?.data?.user?.username + ) { + if (!user?.data?.user?.data?.fcmToken || fcmToken !== user?.data?.user?.data?.fcmToken) { + const res = await axios.put( + `/api/updateUser?userID=${userID}&fcmToken=${fcmToken}&username=${user?.data?.user?.username}` + ); + } + } + } catch (err) { + console.error(err); + } + }; + requestPermission(); + updateUser(); + }, [isAuthenticated]); if (process.env.NODE_ENV === 'production') { globalThis.console.log = () => {}; @@ -87,6 +133,7 @@ const App = ({
+ @@ -102,9 +149,8 @@ const App = ({ App.getInitialProps = async () => { await flagsmith.init({ - api:process.env.NEXT_PUBLIC_FLAGSMITH_API, - environmentID: process.env.NEXT_PUBLIC_ENVIRONMENT_ID - + api: process.env.NEXT_PUBLIC_FLAGSMITH_API, + environmentID: process.env.NEXT_PUBLIC_ENVIRONMENT_ID, }); return { flagsmithState: flagsmith.getState() }; }; diff --git a/apps/amakrushi/src/pages/api/getUser.js b/apps/amakrushi/src/pages/api/getUser.js new file mode 100644 index 00000000..615e7b21 --- /dev/null +++ b/apps/amakrushi/src/pages/api/getUser.js @@ -0,0 +1,23 @@ +export default async function handler(req, res) { + const { userID } = req.query; + + try { + const url = `${process.env.NEXT_PUBLIC_FUS_URL}/api/user/${userID}`; + const response = await fetch(url, { + headers: { + Authorization: process.env.NEXT_PUBLIC_FUS_AUTH, + 'x-application-id': process.env.NEXT_PUBLIC_FUS_APP_ID, + }, + }); + + if (!response.ok) { + throw new Error(`Fetch failed with status ${response.status}`); + } + + const data = await response.json(); + res.status(200).json(data); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Something went wrong' }); + } +} diff --git a/apps/amakrushi/src/pages/api/updateUser.js b/apps/amakrushi/src/pages/api/updateUser.js new file mode 100644 index 00000000..f765ff89 --- /dev/null +++ b/apps/amakrushi/src/pages/api/updateUser.js @@ -0,0 +1,32 @@ +const axios = require('axios'); + +export default async function handler(req, res) { + const { userID, fcmToken, username } = req.query; + + try { + const url = `${process.env.NEXT_PUBLIC_FUS_URL}/api/user/${userID}`; + const response = await axios.put(url, { + user:{ + username: username, + data:{ + fcmToken: fcmToken + } + } + },{ + headers: { + Authorization: process.env.NEXT_PUBLIC_FUS_AUTH, + 'x-application-id': process.env.NEXT_PUBLIC_FUS_APP_ID, + }, + }); + + if (!response.ok) { + throw new Error(`Updation failed with status ${response.status}`); + } + + const data = await response.json(); + res.status(200).json(data); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Something went wrong' }); + } +} diff --git a/apps/amakrushi/src/utils/FcmNotification.tsx b/apps/amakrushi/src/utils/FcmNotification.tsx new file mode 100644 index 00000000..0b81ef0d --- /dev/null +++ b/apps/amakrushi/src/utils/FcmNotification.tsx @@ -0,0 +1,34 @@ +import React, {useState, useEffect} from 'react' +import toast, { Toaster } from 'react-hot-toast'; +import { onMessageListener } from './firebase'; + +const FcmNotification = () => { + const [notification, setNotification] = useState({title: '', body: ''}); + const notify = () => toast(); + function ToastDisplay() { + return ( +
+

{notification?.title}

+

{notification?.body}

+
+ ); + }; + + useEffect(() => { + if (notification?.title ){ + notify() + } + }, [notification]) + + onMessageListener() + .then((payload) => { + setNotification({title: payload?.notification?.title, body: payload?.notification?.body}); + }) + .catch((err) => console.log('failed: ', err)); + + return ( + + ) +} + +export default FcmNotification \ No newline at end of file diff --git a/apps/amakrushi/src/utils/firebase.ts b/apps/amakrushi/src/utils/firebase.ts index 2c7b6d12..9fe4ab20 100644 --- a/apps/amakrushi/src/utils/firebase.ts +++ b/apps/amakrushi/src/utils/firebase.ts @@ -1,5 +1,6 @@ import { initializeApp } from 'firebase/app'; import { getAnalytics } from 'firebase/analytics'; +import { getMessaging, onMessage } from 'firebase/messaging' const firebaseConfig = { apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, @@ -13,3 +14,10 @@ const firebaseConfig = { const app = initializeApp(firebaseConfig); export const analytics = typeof window !== 'undefined' ? getAnalytics(app) : null; +export const messaging = typeof window !== 'undefined' ? getMessaging(app) : null; +export const onMessageListener = () => + new Promise((resolve) => { + onMessage(messaging, (payload) => { + resolve(payload); + }); + }); \ No newline at end of file diff --git a/apps/amakrushi/src/utils/serviceWorker.ts b/apps/amakrushi/src/utils/serviceWorker.ts index ad1d5720..0eb129aa 100644 --- a/apps/amakrushi/src/utils/serviceWorker.ts +++ b/apps/amakrushi/src/utils/serviceWorker.ts @@ -11,139 +11,149 @@ // opt-in, read https://cra.link/PWA const isLocalhost = Boolean( - window.location.hostname === "localhost" || - // [::1] is the IPv6 localhost address. - window.location.hostname === "[::1]" || - // 127.0.0.0/8 are considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) - ); - - type Config = { - onSuccess?: (registration: ServiceWorkerRegistration) => void; - onUpdate?: (registration: ServiceWorkerRegistration) => void; - }; - - export function register(config?: Config) { - if (process.env.NODE_ENV === "production" && "serviceWorker" in navigator) { - // The URL constructor is available in all browsers that support SW. - - // const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); - const publicUrl = new URL(window.location.href); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebook/create-react-app/issues/2374 - return; - } - - window.addEventListener("load", () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (isLocalhost) { - // This is running on localhost. Let's check if a service worker still exists or not. - checkValidServiceWorker(swUrl, config); - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - "This web app is being served cache-first by a service " + - "worker. To learn more, visit https://cra.link/PWA" - ); - }); - } else { - // Is not localhost. Just register service worker - registerValidSW(swUrl, config); - } - }); + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match( + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) +); + +type Config = { + onSuccess?: (registration: ServiceWorkerRegistration) => void; + onUpdate?: (registration: ServiceWorkerRegistration) => void; +}; + +export function register(config?: Config) { + if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + + // const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + const publicUrl = new URL(window.location.href); + if (publicUrl.origin !== window.location.origin) { + // Our service worker won't work if PUBLIC_URL is on a different origin + // from what our page is served on. This might happen if a CDN is used to + // serve assets; see https://github.com/facebook/create-react-app/issues/2374 + return; } + + // Convert environment variables to URL `search` parameters + const firebaseConfig = new URLSearchParams({ + apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, + authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, + projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, + storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, + messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, + appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, + measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, + }).toString(); + + window.addEventListener('load', () => { + const swUrl = `${process.env.PUBLIC_URL}/firebase-messaging-sw.js?${firebaseConfig}`; + console.log('registering service worker') + if (isLocalhost) { + // This is running on localhost. Let's check if a service worker still exists or not. + checkValidServiceWorker(swUrl, config); + + // Add some additional logging to localhost, pointing developers to the + // service worker/PWA documentation. + navigator.serviceWorker.ready.then(() => { + console.log( + 'This web app is being served cache-first by a service ' + + 'worker. To learn more, visit https://cra.link/PWA' + ); + }); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); } - - function registerValidSW(swUrl: string, config?: Config) { - navigator.serviceWorker - .register(swUrl) - .then((registration) => { - registration.onupdatefound = () => { - const installingWorker = registration.installing; - if (installingWorker == null) { - return; - } - installingWorker.onstatechange = () => { - if (installingWorker.state === "installed") { - if (navigator.serviceWorker.controller) { - // At this point, the updated precached content has been fetched, - // but the previous service worker will still serve the older - // content until all client tabs are closed. - console.log( - "New content is available and will be used when all " + - "tabs for this page are closed. See https://cra.link/PWA." - ); - - // Execute callback - if (config && config.onUpdate) { - config.onUpdate(registration); - } - } else { - // At this point, everything has been precached. - // It is the perfect time to display a - // "Content is cached for offline use." message. - console.log("Content is cached for offline use."); - - // Execute callback - if (config && config.onSuccess) { - config.onSuccess(registration); - } +} + +function registerValidSW(swUrl: string, config?: Config) { + navigator.serviceWorker + .register(swUrl) + .then((registration) => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // At this point, the updated precached content has been fetched, + // but the previous service worker will still serve the older + // content until all client tabs are closed. + console.log( + 'New content is available and will be used when all ' + + 'tabs for this page are closed. See https://cra.link/PWA.' + ); + + // Execute callback + if (config && config.onUpdate) { + config.onUpdate(registration); + } + } else { + // At this point, everything has been precached. + // It is the perfect time to display a + // "Content is cached for offline use." message. + console.log('Content is cached for offline use.'); + + // Execute callback + if (config && config.onSuccess) { + config.onSuccess(registration); } } - }; + } }; - }) - .catch((error) => { - console.error("Error during service worker registration:", error); - }); - } - - function checkValidServiceWorker(swUrl: string, config?: Config) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl, { - headers: { "Service-Worker": "script" }, + }; }) - .then((response) => { - // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get("content-type"); - if ( - response.status === 404 || - (contentType != null && contentType.indexOf("javascript") === -1) - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then((registration) => { - registration.unregister().then(() => { - window.location.reload(); - }); + .catch((error) => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl: string, config?: Config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl, { + headers: { 'Service-Worker': 'script' }, + }) + .then((response) => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then((registration) => { + registration.unregister().then(() => { + window.location.reload(); }); - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl, config); - } + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log( + 'No internet connection found. App is running in offline mode.' + ); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready + .then((registration) => { + registration.unregister(); }) - .catch(() => { - console.log( - "No internet connection found. App is running in offline mode." - ); + .catch((error) => { + console.error(error.message); }); } - - export function unregister() { - if ("serviceWorker" in navigator) { - navigator.serviceWorker.ready - .then((registration) => { - registration.unregister(); - }) - .catch((error) => { - console.error(error.message); - }); - } - } - \ No newline at end of file +} diff --git a/apps/amakrushi/tsconfig.json b/apps/amakrushi/tsconfig.json index 072c7606..acc3586a 100644 --- a/apps/amakrushi/tsconfig.json +++ b/apps/amakrushi/tsconfig.json @@ -26,7 +26,7 @@ "**/*.ts", "**/*.tsx", "**/*.d.ts", - "src/pages/camera.js" ], + "src/pages/camera.js", "public/firebase-messaging-sw.js" ], "exclude": [ "node_modules" ], diff --git a/turbo.json b/turbo.json index 01015172..31227375 100644 --- a/turbo.json +++ b/turbo.json @@ -19,7 +19,11 @@ "NODE_ENV", "NEXT_PUBLIC_ENV", "NEXT_PUBLIC_USER_SERVICE_APP_ID", - "NEXT_PUBLIC_JWKS_URI" + "NEXT_PUBLIC_JWKS_URI", + "NEXT_PUBLIC_FCM_VAPID_KEY", + "NEXT_PUBLIC_FUS_APP_ID", + "NEXT_PUBLIC_FUS_URL", + "NEXT_PUBLIC_FUS_AUTH" ], "globalDependencies": ["**/.env.*local"], From b4e863b4c7a4cfa5cf745707d9bb241642f7d180 Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Mon, 29 May 2023 13:20:58 +0530 Subject: [PATCH 14/25] fix: update in conversation api (#135) --- apps/amakrushi/src/components/HistoryPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/amakrushi/src/components/HistoryPage/index.tsx b/apps/amakrushi/src/components/HistoryPage/index.tsx index 419216e3..0f7c98fe 100644 --- a/apps/amakrushi/src/components/HistoryPage/index.tsx +++ b/apps/amakrushi/src/components/HistoryPage/index.tsx @@ -32,7 +32,7 @@ const HistoryPage: NextPage = () => { }) .then((res) => { const sortedConversations = _.filter( - res?.data, + res?.data?.userHistory, (conv) => conv?.conversationId !== null ).sort( //@ts-ignore From 5caf66fa8d5ecf63c5a946e38804a1b5e78a2f0a Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Mon, 29 May 2023 16:38:02 +0530 Subject: [PATCH 15/25] fix: added firebase event for msg delay (#136) --- .../amakrushi/src/context/ContextProvider.tsx | 61 ++++++++++++------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index 2a3e0955..daf584ce 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -242,7 +242,10 @@ const ContextProvider: FC<{ //@ts-ignore const sendMessage = useCallback( (text: string, media: any, isVisibile = true): void => { - if(!localStorage.getItem('userID') || !sessionStorage.getItem('conversationId')){ + if ( + !localStorage.getItem('userID') || + !sessionStorage.getItem('conversationId') + ) { removeCookie('access_token', { path: '/' }); location?.reload(); return; @@ -302,29 +305,36 @@ const ContextProvider: FC<{ // console.log('mssgs:',messages) } }, - [newSocket, socketSession, conversationId, t, onSocketConnect, currentUser?.id] + [ + newSocket, + socketSession, + conversationId, + t, + onSocketConnect, + currentUser?.id, + ] ); const fetchIsDown = useCallback(async () => { - try { - const res = await axios.get( - `${process.env.NEXT_PUBLIC_BASE_URL}/health/${flags?.health_check_time?.value}` - ); - const status = res.data.status; - console.log('hie', status); - if (status === 'OK') { - setIsDown(false); - } else { - setIsDown(true); - console.log('Server status is not OK'); - } - } catch (error) { - //@ts-ignore - logEvent(analytics, 'console_error', { - error_message: error.message, - }); + try { + const res = await axios.get( + `${process.env.NEXT_PUBLIC_BASE_URL}/health/${flags?.health_check_time?.value}` + ); + const status = res.data.status; + console.log('hie', status); + if (status === 'OK') { + setIsDown(false); + } else { + setIsDown(true); + console.log('Server status is not OK'); } - }, [setIsDown, flags]); + } catch (error) { + //@ts-ignore + logEvent(analytics, 'console_error', { + error_message: error.message, + }); + } + }, [setIsDown, flags]); useEffect(() => { if (!socketSession && newSocket) { @@ -351,6 +361,11 @@ const ContextProvider: FC<{ setIsMsgReceiving(false); setLoading(false); fetchIsDown(); + //@ts-ignore + logEvent(analytics, 'msg_delay', { + user_id: localStorage.getItem('userID'), + phone_number: localStorage.getItem('phoneNumber'), + }); } }, timer2); } @@ -386,7 +401,7 @@ const ContextProvider: FC<{ isDown, fetchIsDown, showDialerPopup, - setShowDialerPopup + setShowDialerPopup, }), [ locale, @@ -410,7 +425,7 @@ const ContextProvider: FC<{ isDown, fetchIsDown, showDialerPopup, - setShowDialerPopup + setShowDialerPopup, ] ); @@ -452,4 +467,4 @@ const SSR: FC<{ children: ReactElement }> = ({ children }) => { ); }; -export default SSR; \ No newline at end of file +export default SSR; From cd312828401bfa82e5bdd61f60222681f74a9ccd Mon Sep 17 00:00:00 2001 From: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> Date: Thu, 1 Jun 2023 13:22:46 +0530 Subject: [PATCH 16/25] fix: flagsmith init inside useeffect (#140) * fix: flagsmith init inside useeffect * added flagsmith cloud --------- Co-authored-by: Prateek Jakhar --- apps/amakrushi/src/pages/_app.tsx | 45 ++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/apps/amakrushi/src/pages/_app.tsx b/apps/amakrushi/src/pages/_app.tsx index 25bdf475..be6e773e 100644 --- a/apps/amakrushi/src/pages/_app.tsx +++ b/apps/amakrushi/src/pages/_app.tsx @@ -36,19 +36,37 @@ function SafeHydrate({ children }: { children: ReactElement }) { const App = ({ Component, pageProps, - flagsmithState, -}: AppProps & { flagsmithState: any }) => { +}: AppProps) => { const router = useRouter(); const { isAuthenticated, login } = useLogin(); const [launch, setLaunch] = useState(true); const [cookie, setCookie, removeCookie] = useCookies(); - +const [flagsmithState, setflagsmithState] = useState(null) useEffect(() => { setTimeout(() => { setLaunch(false); }, 2500); }, []); + + useEffect(() =>{ + const getFlagSmithState =async ()=>{ + await flagsmith.init({ + // api: process.env.NEXT_PUBLIC_FLAGSMITH_API, + environmentID: process.env.NEXT_PUBLIC_ENVIRONMENT_ID || '', + }) + if(flagsmith.getState()) + { + //@ts-ignore + setflagsmithState(flagsmith.getState()) + } + } + getFlagSmithState() + + },[]) + + + const handleLoginRedirect = useCallback(() => { if (router.pathname === '/login' || router.pathname.startsWith('/otp')) { // already logged in then send to home @@ -71,7 +89,7 @@ const App = ({ router.push('/login'); } } - }, [cookie, removeCookie, router]); + }, [cookie, router]); useEffect(() => { handleLoginRedirect(); @@ -125,7 +143,9 @@ const App = ({ globalThis.console.log = () => {}; } - if (launch) { + console.log({flagsmithState}) + + if (launch || !flagsmithState) { return ; } else { return ( @@ -147,11 +167,12 @@ const App = ({ } }; -App.getInitialProps = async () => { - await flagsmith.init({ - api: process.env.NEXT_PUBLIC_FLAGSMITH_API, - environmentID: process.env.NEXT_PUBLIC_ENVIRONMENT_ID, - }); - return { flagsmithState: flagsmith.getState() }; -}; +// App.getInitialProps = async () => { +// await flagsmith.init({ +// api: process.env.NEXT_PUBLIC_FLAGSMITH_API, +// environmentID: process.env.NEXT_PUBLIC_ENVIRONMENT_ID, +// }); +// return { flagsmithState: flagsmith.getState() }; +// }; + export default App; From 8b9f2821d0c3a478e0650daa91f8bd4cffa2ce02 Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Fri, 2 Jun 2023 18:00:44 +0530 Subject: [PATCH 17/25] Added query log and splash screen log (#143) --- apps/amakrushi/src/context/ContextProvider.tsx | 4 +++- apps/amakrushi/src/pages/_app.tsx | 15 +++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index daf584ce..4d3f9b7d 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -275,6 +275,8 @@ const ContextProvider: FC<{ ); return; } + //@ts-ignore + logEvent(analytics, 'Query_sent'); // console.log('mssgs:',messages) send({ text, socketSession, socket: newSocket, conversationId }); if (isVisibile) @@ -362,7 +364,7 @@ const ContextProvider: FC<{ setLoading(false); fetchIsDown(); //@ts-ignore - logEvent(analytics, 'msg_delay', { + logEvent(analytics, 'Msg_delay', { user_id: localStorage.getItem('userID'), phone_number: localStorage.getItem('phoneNumber'), }); diff --git a/apps/amakrushi/src/pages/_app.tsx b/apps/amakrushi/src/pages/_app.tsx index 0e7d30da..b5a5a4e3 100644 --- a/apps/amakrushi/src/pages/_app.tsx +++ b/apps/amakrushi/src/pages/_app.tsx @@ -15,9 +15,10 @@ import { FlagsmithProvider } from 'flagsmith/react'; import { useLogin } from '../hooks'; import axios from 'axios'; -import { messaging } from '../utils/firebase'; +import { messaging, analytics } from '../utils/firebase'; import { getToken } from 'firebase/messaging'; import FcmNotification from '../utils/FcmNotification'; +import { logEvent } from 'firebase/analytics'; const LaunchPage = dynamic(() => import('../components/LaunchPage'), { ssr: false, @@ -42,16 +43,22 @@ const App = ({ const { isAuthenticated, login } = useLogin(); const [launch, setLaunch] = useState(true); const [cookie, setCookie, removeCookie] = useCookies(); - - const [flagsmithState, setflagsmithState] = useState(null) - + const [flagsmithState, setflagsmithState] = useState(null); useEffect(() => { + const isEventLogged = sessionStorage.getItem('isSplashScreenLogged'); + if (!isEventLogged) { + //@ts-ignore + logEvent(analytics, 'Splash_screen'); + sessionStorage.setItem('isSplashScreenLogged', 'true'); + } + setTimeout(() => { setLaunch(false); }, 2500); }, []); + useEffect(() =>{ From 3c7998741697f0e3f6d1695fa984cc1929d3a280 Mon Sep 17 00:00:00 2001 From: Prateek Jakhar Date: Mon, 5 Jun 2023 17:48:56 +0530 Subject: [PATCH 18/25] Feat trans (#134) * feat: mic button working * feat: audio to speech added * chore: ui changes * chore: ui changes * feat: speech to text added to chat ui * added flagsmith for model ids * feat: transliteration added * style: changed translate to transliterate * style: changed translate text to transliterate * feat: added eng dictionary * feat: added eng dictionary * added flagsmith cloud * added conv. api change * chore: removed dictionary, now transliterating every msg * fix: transliteration added in or only * fix: added transliteration only on or lang * minor ui changes * minor ui changes --------- Co-authored-by: Saiyan Abhishek <74703491+geeky-abhishek@users.noreply.github.com> --- apps/amakrushi/package.json | 1 + .../src/components/HomePage/index.module.css | 1 + .../src/components/HomePage/index.tsx | 119 +++-- .../PhoneView/ChatWindow/ChatUiWindow.tsx | 121 +++-- .../src/components/down-time-page/index.tsx | 3 +- .../amakrushi/src/context/ContextProvider.tsx | 3 + apps/amakrushi/src/pages/_app.tsx | 1 - apps/amakrushi/src/pages/index.tsx | 2 + package-lock.json | 472 ++++++++++++++++++ packages/chat-ui/dist/index.js | 2 +- packages/chat-ui/es/components/Chat/index.js | 6 +- .../chat-ui/es/components/Composer/index.js | 6 +- packages/chat-ui/lib/components/Chat/index.js | 6 +- .../chat-ui/lib/components/Composer/index.js | 6 +- .../chat-ui/src/components/Chat/index.tsx | 12 +- .../chat-ui/src/components/Composer/index.tsx | 9 +- turbo.json | 1 + yarn.lock | 184 ++++++- 18 files changed, 864 insertions(+), 91 deletions(-) diff --git a/apps/amakrushi/package.json b/apps/amakrushi/package.json index ec4d93c9..57c4360d 100644 --- a/apps/amakrushi/package.json +++ b/apps/amakrushi/package.json @@ -16,6 +16,7 @@ "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@magicbell/magicbell-react": "^8.5.3", + "@material-ui/core": "^4.12.4", "@next/bundle-analyzer": "^13.3.0", "@storybook/react": "^6.5.9", "@testing-library/jest-dom": "^5.16.2", diff --git a/apps/amakrushi/src/components/HomePage/index.module.css b/apps/amakrushi/src/components/HomePage/index.module.css index 081b6dc1..dd4a9112 100644 --- a/apps/amakrushi/src/components/HomePage/index.module.css +++ b/apps/amakrushi/src/components/HomePage/index.module.css @@ -79,3 +79,4 @@ border-radius: 40px !important; background-color: var(--secondarygreen) !important; } + diff --git a/apps/amakrushi/src/components/HomePage/index.tsx b/apps/amakrushi/src/components/HomePage/index.tsx index 610583da..a87396ab 100644 --- a/apps/amakrushi/src/components/HomePage/index.tsx +++ b/apps/amakrushi/src/components/HomePage/index.tsx @@ -1,35 +1,36 @@ -import styles from './index.module.css'; +import styles from "./index.module.css"; import React, { useCallback, useContext, useEffect, useMemo, useState, -} from 'react'; -import { NextPage } from 'next'; - +} from "react"; +import { NextPage } from "next"; +import axios from "axios"; //@ts-ignore -import { analytics } from '../../utils/firebase'; -import { logEvent } from 'firebase/analytics'; -import Menu from '../menu'; -import { getInitialMsgs } from '../../utils/textUtility'; -import { AppContext } from '../../context'; -import RightIcon from '../../assets/icons/right'; -import sunIcon from '../../assets/icons/sun.svg'; -import reloadIcon from '../../assets/icons/reload.svg'; -import { useLocalization } from '../../hooks'; -import router from 'next/router'; -import Image from 'next/image'; -import { Button } from '@chakra-ui/react'; -import toast from 'react-hot-toast'; -import { v4 as uuidv4 } from 'uuid'; +import { analytics } from "../../utils/firebase"; +import { logEvent } from "firebase/analytics"; +import Menu from "../menu"; +import { getInitialMsgs } from "../../utils/textUtility"; +import { AppContext } from "../../context"; + +import RightIcon from "../../assets/icons/right"; +import sunIcon from "../../assets/icons/sun.svg"; +import reloadIcon from "../../assets/icons/reload.svg"; +import { useLocalization } from "../../hooks"; +import router from "next/router"; +import Image from "next/image"; +import { Button } from "@chakra-ui/react"; +import toast from "react-hot-toast"; +import { v4 as uuidv4 } from "uuid"; const HomePage: NextPage = () => { const context = useContext(AppContext); const t = useLocalization(); - const placeholder = useMemo(() => t('message.ask_ur_question'), [t]); + const placeholder = useMemo(() => t("message.ask_ur_question"), [t]); const [messages, setMessages] = useState>([getInitialMsgs(t)]); - const [inputMsg, setInputMsg] = useState(''); + const [inputMsg, setInputMsg] = useState(""); useEffect(() => { setMessages([getInitialMsgs(t)]); @@ -37,32 +38,74 @@ const HomePage: NextPage = () => { useEffect(() => { //@ts-ignore - logEvent(analytics, 'Home_page'); + logEvent(analytics, "Home_page"); context?.fetchIsDown(); // check if server is down - if(!sessionStorage.getItem('conversationId')){ - const newConversationId = uuidv4(); - sessionStorage.setItem('conversationId', newConversationId); - context?.setConversationId(newConversationId); - } - // eslint-disable-next-line react-hooks/exhaustive-deps + if (!sessionStorage.getItem("conversationId")) { + const newConversationId = uuidv4(); + sessionStorage.setItem("conversationId", newConversationId); + context?.setConversationId(newConversationId); + } + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const sendMessage = useCallback( - (msg: string) => { + async (msg: string) => { if (msg.length === 0) { - toast.error(t('error.empty_msg')); + toast.error(t("error.empty_msg")); return; } - if (context?.socketSession && context?.newSocket?.connected) { - console.log('clearing mssgs'); - context?.setMessages([]); - router.push('/chat'); - context?.sendMessage(msg); - } else { - toast.error(t('error.disconnected')); - return; + try { + if (!(localStorage.getItem("locale") === "en")) { + const words = msg.split(" "); + // Call transliteration API + const input = words.map((word) => ({ + source: word, + })); + + const response = await axios.post( + "https://meity-auth.ulcacontrib.org/ulca/apis/v0/model/compute", + { + modelId: process.env.NEXT_PUBLIC_TRANSLITERATION_MODELID, + task: "transliteration", + input: input, + }, + { + headers: { + "Content-Type": "application/json", + }, + } + ); + console.log("transliterated msg: ", response.data.output); + const transliteratedArray = []; + for (const element of response.data.output) { + transliteratedArray.push(element?.target?.[0]); + } + + if (context?.socketSession && context?.newSocket?.connected) { + console.log("clearing mssgs"); + context?.setMessages([]); + router.push("/chat"); + context?.sendMessage(transliteratedArray.join(" ")); + } else { + toast.error(t("error.disconnected")); + return; + } + } else { + if (context?.socketSession && context?.newSocket?.connected) { + console.log("clearing mssgs"); + context?.setMessages([]); + router.push("/chat"); + context?.sendMessage(msg); + } else { + toast.error(t("error.disconnected")); + return; + } + + } + } catch (error) { + console.error(error); } }, [context, t] @@ -112,7 +155,7 @@ const HomePage: NextPage = () => { type="submit" onClick={() => sendMessage(inputMsg)} className={styles.sendButton}> - {t('label.send')} + {t("label.send")}
diff --git a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx index 48c0f7e7..e61959ad 100644 --- a/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx +++ b/apps/amakrushi/src/components/PhoneView/ChatWindow/ChatUiWindow.tsx @@ -1,6 +1,6 @@ -import axios from 'axios'; +import axios from "axios"; //@ts-ignore -import Chat from 'chatui'; +import Chat from "chatui"; import React, { ReactElement, useCallback, @@ -8,46 +8,48 @@ import React, { useEffect, useMemo, useState, -} from 'react'; -import { analytics } from '../../../utils/firebase'; -import { logEvent } from 'firebase/analytics'; -import { AppContext } from '../../../context'; -import { useLocalization } from '../../../hooks'; -import { getMsgType } from '../../../utils/getMsgType'; -import ChatMessageItem from '../../chat-message-item'; -import { v4 as uuidv4 } from 'uuid'; -import DownTimePage from '../../down-time-page'; +} from "react"; +import { analytics } from "../../../utils/firebase"; +import { logEvent } from "firebase/analytics"; +import { AppContext } from "../../../context"; +import { useLocalization } from "../../../hooks"; +import { getMsgType } from "../../../utils/getMsgType"; +import ChatMessageItem from "../../chat-message-item"; +import { v4 as uuidv4 } from "uuid"; +import toast from "react-hot-toast"; +import DownTimePage from "../../down-time-page"; const ChatUiWindow: React.FC = () => { const t = useLocalization(); - const context = useContext(AppContext); + const context = useContext(AppContext); useEffect(() => { const fetchData = async () => { try { await context?.fetchIsDown(); if(!context?.isDown){ - const chatHistory = await axios.get( `${ process.env.NEXT_PUBLIC_BASE_URL - }/user/chathistory/${sessionStorage.getItem('conversationId')}`, + }/user/chathistory/${sessionStorage.getItem("conversationId")}`, { headers: { - authorization: `Bearer ${localStorage.getItem('auth')}`, + authorization: `Bearer ${localStorage.getItem("auth")}`, }, } ); + console.log("ghji:",chatHistory) console.log('history:', chatHistory.data); + const normalizedChats = normalizedChat(chatHistory.data); if (normalizedChats.length > 0) { context?.setMessages(normalizedChats); } } - } catch (error:any) { + } catch (error: any) { //@ts-ignore - logEvent(analytics, 'console_error', { + logEvent(analytics, "console_error", { error_message: error.message, }); } @@ -61,23 +63,23 @@ const ChatUiWindow: React.FC = () => { const normalizedChat = (chats: any): any => { - console.log('in normalized'); - const conversationId = sessionStorage.getItem('conversationId'); + console.log("in normalized"); + const conversationId = sessionStorage.getItem("conversationId"); const history = chats .filter( (item: any) => - conversationId === 'null' || item.conversationId === conversationId + conversationId === "null" || item.conversationId === conversationId ) .flatMap((item: any) => [ { text: item.query, - position: 'right', + position: "right", repliedTimestamp: item.createdAt, messageId: uuidv4(), }, { text: item.response, - position: 'left', + position: "left", sentTimestamp: item.createdAt, reaction: item.reaction, msgId: item.id, @@ -85,52 +87,95 @@ const ChatUiWindow: React.FC = () => { }, ]); - console.log('historyyy', history); - console.log('history length:', history.length); + console.log("historyyy", history); + console.log("history length:", history.length); return history; }; const handleSend = useCallback( - (type: string, val: any) => { - console.log('mssgs:', context?.messages); - if (type === 'text' && val.trim()) { - context?.sendMessage(val.trim()); + async (type: string, msg: any) => { + if (msg.length === 0) { + toast.error(t("error.empty_msg")); + return; + } + console.log("mssgs:", context?.messages); + try { + if (!(localStorage.getItem("locale") === "en")) { + const words = msg.split(" "); + // Call transliteration API + const input = words.map((word: string) => ({ + source: word, + })); + + const response = await axios.post( + "https://meity-auth.ulcacontrib.org/ulca/apis/v0/model/compute", + { + modelId: process.env.NEXT_PUBLIC_TRANSLITERATION_MODELID, + task: "transliteration", + input: input, + }, + { + headers: { + "Content-Type": "application/json", + }, + } + ); + console.log("transliterated msg: ", response.data.output); + const transliteratedArray = []; + for (const element of response.data.output) { + transliteratedArray.push(element?.target?.[0]); + } + + if (context?.socketSession && context?.newSocket?.connected) { + context?.sendMessage(transliteratedArray.join(" ")); + } else { + toast.error(t("error.disconnected")); + return; + } + } else { + if (type === "text" && msg.trim()) { + context?.sendMessage(msg.trim()); + } + } + } catch (error) { + console.error(error); } }, - [context] + [context, t] ); const normalizeMsgs = useMemo( () => context?.messages?.map((msg: any) => ({ type: getMsgType(msg), content: { text: msg?.text, data: { ...msg } }, - position: msg?.position ?? 'right', + position: msg?.position ?? "right", })), [context?.messages] ); - + console.log("fghj:", { messages: context?.messages }); const msgToRender = useMemo(() => { return context?.isMsgReceiving ? [ ...normalizeMsgs, { - type: 'loader', - position: 'left', - botUuid: '1', + type: "loader", + position: "left", + botUuid: "1", }, ] : normalizeMsgs; }, [context?.isMsgReceiving, normalizeMsgs]); - console.log('debug:', { msgToRender }); + console.log("debug:", { msgToRender }); + + const placeholder = useMemo(() => t("message.ask_ur_question"), [t]); - const placeholder = useMemo(() => t('message.ask_ur_question'), [t]); if (context?.isDown) { return ; } else return ( -
+
{ ); }; -export default ChatUiWindow; \ No newline at end of file +export default ChatUiWindow; diff --git a/apps/amakrushi/src/components/down-time-page/index.tsx b/apps/amakrushi/src/components/down-time-page/index.tsx index 8c192b56..d3477046 100644 --- a/apps/amakrushi/src/components/down-time-page/index.tsx +++ b/apps/amakrushi/src/components/down-time-page/index.tsx @@ -27,4 +27,5 @@ function DownTimePage() { ); } -export default DownTimePage; \ No newline at end of file +export default DownTimePage; + diff --git a/apps/amakrushi/src/context/ContextProvider.tsx b/apps/amakrushi/src/context/ContextProvider.tsx index 4d3f9b7d..c03c0ae7 100644 --- a/apps/amakrushi/src/context/ContextProvider.tsx +++ b/apps/amakrushi/src/context/ContextProvider.tsx @@ -121,11 +121,14 @@ const ContextProvider: FC<{ //@ts-ignore if (conversationId === msg?.content?.conversationId) setMessages((prev: any) => _.uniq([...prev, newMsg], ['messageId'])); + } }, [conversationId] ); + console.log("erty:",{conversationId}) + const onMessageReceived = useCallback( (msg: any): void => { console.log('mssgs:', messages); diff --git a/apps/amakrushi/src/pages/_app.tsx b/apps/amakrushi/src/pages/_app.tsx index b5a5a4e3..4be5fd7b 100644 --- a/apps/amakrushi/src/pages/_app.tsx +++ b/apps/amakrushi/src/pages/_app.tsx @@ -185,5 +185,4 @@ const App = ({ // return { flagsmithState: flagsmith.getState() }; // }; - export default App; diff --git a/apps/amakrushi/src/pages/index.tsx b/apps/amakrushi/src/pages/index.tsx index bf0fa003..88a1a221 100644 --- a/apps/amakrushi/src/pages/index.tsx +++ b/apps/amakrushi/src/pages/index.tsx @@ -6,6 +6,7 @@ import { useLocalization } from "../hooks/useLocalization"; import HomePage from "../components/HomePage"; import { useContext, useEffect } from "react"; import { AppContext } from "../context"; +import DownTimePage from "../components/down-time-page"; const Home: NextPage = () => { const t = useLocalization(); @@ -36,6 +37,7 @@ const Home: NextPage = () => { }} > + {/* */}
diff --git a/package-lock.json b/package-lock.json index 5a326e3b..2aec70d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,6 +30,7 @@ "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@magicbell/magicbell-react": "^8.5.3", + "@material-ui/core": "^4.12.4", "@next/bundle-analyzer": "^13.3.0", "@storybook/react": "^6.5.9", "@testing-library/jest-dom": "^5.16.2", @@ -37,6 +38,7 @@ "@testing-library/user-event": "^12.8.3", "@types/jest": "^25.2.3", "@types/node": "^12.20.46", + "audio-react-recorder": "^1.0.4", "axios": "^1.3.5", "bootstrap": "^5.1.3", "chatui": "*", @@ -7617,6 +7619,157 @@ "version": "1.10.8", "license": "MIT" }, + "node_modules/@material-ui/core": { + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/styles/node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "node_modules/@material-ui/styles/node_modules/csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + }, + "node_modules/@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/system/node_modules/csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + }, + "node_modules/@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/@mdn/browser-compat-data": { "version": "5.2.48", "dev": true, @@ -18312,6 +18465,20 @@ "node": ">= 4.5.0" } }, + "node_modules/audio-react-recorder": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/audio-react-recorder/-/audio-react-recorder-1.0.4.tgz", + "integrity": "sha512-an7eX0yOGDbZOSu2LvnfWIsI41pkx9nXgtBVbI+9ByS91WKqoVGVb5pbmqHax5sZty2DjOIG/neuxcghIU/ucg==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.0.0" + } + }, "node_modules/autoprefixer": { "version": "10.4.14", "funding": [ @@ -22036,6 +22203,15 @@ "node": ">=0.10.0" } }, + "node_modules/css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "dependencies": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "node_modules/css-what": { "version": "6.1.0", "license": "BSD-2-Clause", @@ -28130,6 +28306,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" + }, "node_modules/is-installed-globally": { "version": "0.4.0", "dev": true, @@ -31757,6 +31938,88 @@ "verror": "1.10.0" } }, + "node_modules/jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", + "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jss" + } + }, + "node_modules/jss-plugin-camel-case": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", + "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-default-unit": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", + "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-global": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", + "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-nested": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", + "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-props-sort": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", + "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "node_modules/jss-plugin-rule-value-function": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", + "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", + "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.10.0" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "license": "MIT", @@ -37111,6 +37374,11 @@ "tslib": "^2.1.0" } }, + "node_modules/popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "node_modules/posix-character-classes": { "version": "0.1.1", "dev": true, @@ -43351,6 +43619,11 @@ "version": "1.3.1", "license": "MIT" }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "node_modules/tinycolor2": { "version": "1.6.0", "license": "MIT" @@ -52877,6 +53150,93 @@ } } }, + "@material-ui/core": { + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "dependencies": { + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + } + } + }, + "@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.21", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", + "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + } + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" + }, + "@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, "@mdn/browser-compat-data": { "version": "5.2.48", "dev": true @@ -59955,6 +60315,7 @@ "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@magicbell/magicbell-react": "^8.5.3", + "@material-ui/core": "^4.12.4", "@next/bundle-analyzer": "^13.3.0", "@storybook/addon-actions": "^6.4.19", "@storybook/addon-essentials": "^6.4.19", @@ -59976,6 +60337,7 @@ "@types/react-dom": "^18.0.5", "@types/underscore": "^1.11.4", "@types/uuid": "^9.0.1", + "audio-react-recorder": "^1.0.4", "axios": "^1.3.5", "bootstrap": "^5.1.3", "chatui": "*", @@ -60347,6 +60709,14 @@ "version": "2.1.2", "dev": true }, + "audio-react-recorder": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/audio-react-recorder/-/audio-react-recorder-1.0.4.tgz", + "integrity": "sha512-an7eX0yOGDbZOSu2LvnfWIsI41pkx9nXgtBVbI+9ByS91WKqoVGVb5pbmqHax5sZty2DjOIG/neuxcghIU/ucg==", + "requires": { + "prop-types": "^15.7.2" + } + }, "autoprefixer": { "version": "10.4.14", "requires": { @@ -63615,6 +63985,15 @@ } } }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "css-what": { "version": "6.1.0" }, @@ -67961,6 +68340,11 @@ "version": "1.0.4", "dev": true }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==" + }, "is-installed-globally": { "version": "0.4.0", "dev": true, @@ -70527,6 +70911,84 @@ "verror": "1.10.0" } }, + "jss": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.10.0.tgz", + "integrity": "sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz", + "integrity": "sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.10.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz", + "integrity": "sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "jss-plugin-global": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz", + "integrity": "sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "jss-plugin-nested": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz", + "integrity": "sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz", + "integrity": "sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz", + "integrity": "sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.10.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.10.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz", + "integrity": "sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.10.0" + } + }, "jsx-ast-utils": { "version": "3.3.3", "requires": { @@ -74370,6 +74832,11 @@ } } }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "posix-character-classes": { "version": "0.1.1", "dev": true @@ -78322,6 +78789,11 @@ "tiny-invariant": { "version": "1.3.1" }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "tinycolor2": { "version": "1.6.0" }, diff --git a/packages/chat-ui/dist/index.js b/packages/chat-ui/dist/index.js index e93de1db..c947732c 100644 --- a/packages/chat-ui/dist/index.js +++ b/packages/chat-ui/dist/index.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react"),require("react-dom")):"function"==typeof define&&define.amd?define(["exports","react","react-dom"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ChatUI={},e.React,e.ReactDOM)}(this,(function(e,t,n){"use strict";function r(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}e.version="0.0.0";var o=r(t),a=r(n);function i(e){var t,n,r="";if("string"==typeof e||"number"==typeof e)r+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;te.length)&&(t=e.length);for(var n=0,r=new Array(t);n0}});else{var e=function(e){for(var t=window.document,n=o(t);n;)n=o(t=n.ownerDocument);return t}(),t=[],n=null,r=null;i.prototype.THROTTLE_TIMEOUT=100,i.prototype.POLL_INTERVAL=null,i.prototype.USE_MUTATION_OBSERVER=!0,i._setupCrossOriginUpdater=function(){return n||(n=function(e,n){r=e&&n?f(e,n):{top:0,bottom:0,left:0,right:0,width:0,height:0},t.forEach((function(e){e._checkForIntersections()}))}),n},i._resetCrossOriginUpdater=function(){n=null,r=null},i.prototype.observe=function(e){if(!this._observationTargets.some((function(t){return t.element==e}))){if(!e||1!=e.nodeType)throw new Error("target must be an Element");this._registerInstance(),this._observationTargets.push({element:e,entry:null}),this._monitorIntersections(e.ownerDocument),this._checkForIntersections()}},i.prototype.unobserve=function(e){this._observationTargets=this._observationTargets.filter((function(t){return t.element!=e})),this._unmonitorIntersections(e.ownerDocument),0==this._observationTargets.length&&this._unregisterInstance()},i.prototype.disconnect=function(){this._observationTargets=[],this._unmonitorAllIntersections(),this._unregisterInstance()},i.prototype.takeRecords=function(){var e=this._queuedEntries.slice();return this._queuedEntries=[],e},i.prototype._initThresholds=function(e){var t=e||[0];return Array.isArray(t)||(t=[t]),t.sort().filter((function(e,t,n){if("number"!=typeof e||isNaN(e)||e<0||e>1)throw new Error("threshold must be a number between 0 and 1 inclusively");return e!==n[t-1]}))},i.prototype._parseRootMargin=function(e){var t=(e||"0px").split(/\s+/).map((function(e){var t=/^(-?\d*\.?\d+)(px|%)$/.exec(e);if(!t)throw new Error("rootMargin must be specified in pixels or percent");return{value:parseFloat(t[1]),unit:t[2]}}));return t[1]=t[1]||t[0],t[2]=t[2]||t[0],t[3]=t[3]||t[1],t},i.prototype._monitorIntersections=function(t){var n=t.defaultView;if(n&&-1==this._monitoringDocuments.indexOf(t)){var r=this._checkForIntersections,a=null,i=null;this.POLL_INTERVAL?a=n.setInterval(r,this.POLL_INTERVAL):(c(n,"resize",r,!0),c(t,"scroll",r,!0),this.USE_MUTATION_OBSERVER&&"MutationObserver"in n&&(i=new n.MutationObserver(r)).observe(t,{attributes:!0,childList:!0,characterData:!0,subtree:!0})),this._monitoringDocuments.push(t),this._monitoringUnsubscribes.push((function(){var e=t.defaultView;e&&(a&&e.clearInterval(a),u(e,"resize",r,!0)),u(t,"scroll",r,!0),i&&i.disconnect()}));var l=this.root&&(this.root.ownerDocument||this.root)||e;if(t!=l){var s=o(t);s&&this._monitorIntersections(s.ownerDocument)}}},i.prototype._unmonitorIntersections=function(t){var n=this._monitoringDocuments.indexOf(t);if(-1!=n){var r=this.root&&(this.root.ownerDocument||this.root)||e,a=this._observationTargets.some((function(e){var n=e.element.ownerDocument;if(n==t)return!0;for(;n&&n!=r;){var a=o(n);if((n=a&&a.ownerDocument)==t)return!0}return!1}));if(!a){var i=this._monitoringUnsubscribes[n];if(this._monitoringDocuments.splice(n,1),this._monitoringUnsubscribes.splice(n,1),i(),t!=r){var c=o(t);c&&this._unmonitorIntersections(c.ownerDocument)}}}},i.prototype._unmonitorAllIntersections=function(){var e=this._monitoringUnsubscribes.slice(0);this._monitoringDocuments.length=0,this._monitoringUnsubscribes.length=0;for(var t=0;t=0&&h>=0&&{top:u,bottom:s,left:d,right:m,width:v,height:h}||null),!g)break;y=y&&p(y)}return g}},i.prototype._getRootRect=function(){var t;if(this.root&&!m(this.root))t=l(this.root);else{var n=m(this.root)?this.root:e,r=n.documentElement,o=n.body;t={top:0,left:0,right:r.clientWidth||o.clientWidth,width:r.clientWidth||o.clientWidth,bottom:r.clientHeight||o.clientHeight,height:r.clientHeight||o.clientHeight}}return this._expandRectByRootMargin(t)},i.prototype._expandRectByRootMargin=function(e){var t=this._rootMarginValues.map((function(t,n){return"px"==t.unit?t.value:t.value*(n%2?e.width:e.height)/100})),n={top:e.top-t[0],right:e.right+t[1],bottom:e.bottom+t[2],left:e.left-t[3]};return n.width=n.right-n.left,n.height=n.bottom-n.top,n},i.prototype._hasCrossedThreshold=function(e,t){var n=e&&e.isIntersecting?e.intersectionRatio||0:-1,r=t.isIntersecting?t.intersectionRatio||0:-1;if(n!==r)for(var o=0;o1?n-1:0),o=1;o/gm),Z=b(/\${[\w\W]*}/gm),ee=b(/^data-[\-\w.\u00B7-\uFFFF]/),te=b(/^aria-[\-\w]+$/),ne=b(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),re=b(/^(?:\w+script|data):/i),oe=b(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),ae=b(/^html$/i),ie=function(){return"undefined"==typeof window?null:window};var ce=function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:ie(),n=function(t){return e(t)};if(n.version="2.4.5",n.removed=[],!t||!t.document||9!==t.document.nodeType)return n.isSupported=!1,n;var r=t.document,o=t.document,a=t.DocumentFragment,i=t.HTMLTemplateElement,c=t.Node,l=t.Element,s=t.NodeFilter,d=t.NamedNodeMap,p=void 0===d?t.NamedNodeMap||t.MozNamedAttrMap:d,m=t.HTMLFormElement,v=t.DOMParser,h=t.trustedTypes,g=l.prototype,b=H(g,"cloneNode"),E=H(g,"nextSibling"),w=H(g,"childNodes"),x=H(g,"parentNode");if("function"==typeof i){var N=o.createElement("template");N.content&&N.content.ownerDocument&&(o=N.content.ownerDocument)}var S=function(e,t){if("object"!==u(e)||"function"!=typeof e.createPolicy)return null;var n=null,r="data-tt-policy-suffix";t.currentScript&&t.currentScript.hasAttribute(r)&&(n=t.currentScript.getAttribute(r));var o="dompurify"+(n?"#"+n:"");try{return e.createPolicy(o,{createHTML:function(e){return e},createScriptURL:function(e){return e}})}catch(e){return null}}(h,r),P=S?S.createHTML(""):"",ce=o,ue=ce.implementation,le=ce.createNodeIterator,se=ce.createDocumentFragment,fe=ce.getElementsByTagName,de=r.importNode,pe={};try{pe=F(o).documentMode?o.documentMode:{}}catch(e){}var me={};n.isSupported="function"==typeof x&&ue&&void 0!==ue.createHTMLDocument&&9!==pe;var ve,he,ge=J,ye=Q,be=Z,Ee=ee,we=te,xe=re,Ne=oe,Se=ne,Te=null,Ce=D({},[].concat(f(B),f(U),f(z),f(V),f(Y))),Oe=null,Re=D({},[].concat(f(X),f(q),f($),f(K))),ke=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Ie=null,Ae=null,Me=!0,_e=!0,Le=!1,je=!0,Pe=!1,De=!1,Fe=!1,He=!1,Be=!1,Ue=!1,ze=!1,Ge=!0,Ve=!1,We=!0,Ye=!1,Xe={},qe=null,$e=D({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),Ke=null,Je=D({},["audio","video","img","source","image","track"]),Qe=null,Ze=D({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),et="http://www.w3.org/1998/Math/MathML",tt="http://www.w3.org/2000/svg",nt="http://www.w3.org/1999/xhtml",rt=nt,ot=!1,at=null,it=D({},[et,tt,nt],k),ct=["application/xhtml+xml","text/html"],ut=null,lt=o.createElement("form"),st=function(e){return e instanceof RegExp||e instanceof Function},ft=function(e){ut&&ut===e||(e&&"object"===u(e)||(e={}),e=F(e),ve=ve=-1===ct.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,he="application/xhtml+xml"===ve?k:R,Te="ALLOWED_TAGS"in e?D({},e.ALLOWED_TAGS,he):Ce,Oe="ALLOWED_ATTR"in e?D({},e.ALLOWED_ATTR,he):Re,at="ALLOWED_NAMESPACES"in e?D({},e.ALLOWED_NAMESPACES,k):it,Qe="ADD_URI_SAFE_ATTR"in e?D(F(Ze),e.ADD_URI_SAFE_ATTR,he):Ze,Ke="ADD_DATA_URI_TAGS"in e?D(F(Je),e.ADD_DATA_URI_TAGS,he):Je,qe="FORBID_CONTENTS"in e?D({},e.FORBID_CONTENTS,he):$e,Ie="FORBID_TAGS"in e?D({},e.FORBID_TAGS,he):{},Ae="FORBID_ATTR"in e?D({},e.FORBID_ATTR,he):{},Xe="USE_PROFILES"in e&&e.USE_PROFILES,Me=!1!==e.ALLOW_ARIA_ATTR,_e=!1!==e.ALLOW_DATA_ATTR,Le=e.ALLOW_UNKNOWN_PROTOCOLS||!1,je=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,Pe=e.SAFE_FOR_TEMPLATES||!1,De=e.WHOLE_DOCUMENT||!1,Be=e.RETURN_DOM||!1,Ue=e.RETURN_DOM_FRAGMENT||!1,ze=e.RETURN_TRUSTED_TYPE||!1,He=e.FORCE_BODY||!1,Ge=!1!==e.SANITIZE_DOM,Ve=e.SANITIZE_NAMED_PROPS||!1,We=!1!==e.KEEP_CONTENT,Ye=e.IN_PLACE||!1,Se=e.ALLOWED_URI_REGEXP||Se,rt=e.NAMESPACE||nt,ke=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&st(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(ke.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&st(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(ke.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(ke.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Pe&&(_e=!1),Ue&&(Be=!0),Xe&&(Te=D({},f(Y)),Oe=[],!0===Xe.html&&(D(Te,B),D(Oe,X)),!0===Xe.svg&&(D(Te,U),D(Oe,q),D(Oe,K)),!0===Xe.svgFilters&&(D(Te,z),D(Oe,q),D(Oe,K)),!0===Xe.mathMl&&(D(Te,V),D(Oe,$),D(Oe,K))),e.ADD_TAGS&&(Te===Ce&&(Te=F(Te)),D(Te,e.ADD_TAGS,he)),e.ADD_ATTR&&(Oe===Re&&(Oe=F(Oe)),D(Oe,e.ADD_ATTR,he)),e.ADD_URI_SAFE_ATTR&&D(Qe,e.ADD_URI_SAFE_ATTR,he),e.FORBID_CONTENTS&&(qe===$e&&(qe=F(qe)),D(qe,e.FORBID_CONTENTS,he)),We&&(Te["#text"]=!0),De&&D(Te,["html","head","body"]),Te.table&&(D(Te,["tbody"]),delete Ie.tbody),y&&y(e),ut=e)},dt=D({},["mi","mo","mn","ms","mtext"]),pt=D({},["foreignobject","desc","title","annotation-xml"]),mt=D({},["title","style","font","a","script"]),vt=D({},U);D(vt,z),D(vt,G);var ht=D({},V);D(ht,W);var gt=function(e){O(n.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){try{e.outerHTML=P}catch(t){e.remove()}}},yt=function(e,t){try{O(n.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){O(n.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Oe[e])if(Be||Ue)try{gt(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},bt=function(e){var t,n;if(He)e=""+e;else{var r=I(e,/^[\r\n\t ]+/);n=r&&r[0]}"application/xhtml+xml"===ve&&rt===nt&&(e=''+e+"");var a=S?S.createHTML(e):e;if(rt===nt)try{t=(new v).parseFromString(a,ve)}catch(e){}if(!t||!t.documentElement){t=ue.createDocument(rt,"template",null);try{t.documentElement.innerHTML=ot?P:a}catch(e){}}var i=t.body||t.documentElement;return e&&n&&i.insertBefore(o.createTextNode(n),i.childNodes[0]||null),rt===nt?fe.call(t,De?"html":"body")[0]:De?t.documentElement:i},Et=function(e){return le.call(e.ownerDocument||e,e,s.SHOW_ELEMENT|s.SHOW_COMMENT|s.SHOW_TEXT,null,!1)},wt=function(e){return"object"===u(c)?e instanceof c:e&&"object"===u(e)&&"number"==typeof e.nodeType&&"string"==typeof e.nodeName},xt=function(e,t,r){me[e]&&T(me[e],(function(e){e.call(n,t,r,ut)}))},Nt=function(e){var t,r;if(xt("beforeSanitizeElements",e,null),(r=e)instanceof m&&("string"!=typeof r.nodeName||"string"!=typeof r.textContent||"function"!=typeof r.removeChild||!(r.attributes instanceof p)||"function"!=typeof r.removeAttribute||"function"!=typeof r.setAttribute||"string"!=typeof r.namespaceURI||"function"!=typeof r.insertBefore||"function"!=typeof r.hasChildNodes))return gt(e),!0;if(L(/[\u0080-\uFFFF]/,e.nodeName))return gt(e),!0;var o=he(e.nodeName);if(xt("uponSanitizeElement",e,{tagName:o,allowedTags:Te}),e.hasChildNodes()&&!wt(e.firstElementChild)&&(!wt(e.content)||!wt(e.content.firstElementChild))&&L(/<[/\w]/g,e.innerHTML)&&L(/<[/\w]/g,e.textContent))return gt(e),!0;if("select"===o&&L(/