From ccdf532517e50e40ae0d0645c6c836360152813f Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Tue, 11 Jul 2023 18:37:49 +0530 Subject: [PATCH 1/9] fix: fix unable to decrypt case (#527) --- .../restapi/src/lib/chat/helpers/crypto.ts | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/restapi/src/lib/chat/helpers/crypto.ts b/packages/restapi/src/lib/chat/helpers/crypto.ts index 3282fd074..86e64b590 100644 --- a/packages/restapi/src/lib/chat/helpers/crypto.ts +++ b/packages/restapi/src/lib/chat/helpers/crypto.ts @@ -420,21 +420,27 @@ export const decryptAndVerifyMessage = async ( * 2. Decrypt messageObj.message, messageObj.meta , messageContent */ const decryptedMessage: IMessageIPFS | IMessageIPFSWithCID = { ...message }; - const secretKey: string = await pgpDecrypt({ - cipherText: message.encryptedSecret, - toPrivateKeyArmored: pgpPrivateKey, - }); - decryptedMessage.messageContent = aesDecrypt({ - cipherText: message.messageContent, - secretKey, - }); - if (message.messageObj) { - decryptedMessage.messageObj = JSON.parse( - aesDecrypt({ - cipherText: message.messageObj as string, - secretKey, - }) - ); + try { + const secretKey: string = await pgpDecrypt({ + cipherText: message.encryptedSecret, + toPrivateKeyArmored: pgpPrivateKey, + }); + decryptedMessage.messageContent = aesDecrypt({ + cipherText: message.messageContent, + secretKey, + }); + if (message.messageObj) { + decryptedMessage.messageObj = JSON.parse( + aesDecrypt({ + cipherText: message.messageObj as string, + secretKey, + }) + ); + } + } catch (err) { + decryptedMessage.messageContent = decryptedMessage.messageObj = + 'Unable to Decrypt Message'; } + return decryptedMessage; }; From 90b32f0daae459f498f7b3d0dcb2b8e2fccd95fb Mon Sep 17 00:00:00 2001 From: Firas Mumtaz <72166289+firascodes@users.noreply.github.com> Date: Thu, 13 Jul 2023 02:56:50 +0530 Subject: [PATCH 2/9] Create Readme.md --- packages/examples/Readme.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 packages/examples/Readme.md diff --git a/packages/examples/Readme.md b/packages/examples/Readme.md new file mode 100644 index 000000000..09b967e62 --- /dev/null +++ b/packages/examples/Readme.md @@ -0,0 +1,17 @@ +# Welcome to Push SDK Examples! + +## One-Stop Solution for Understanding the Implementation of Push Protocol's SDK + +The `push-sdk` repository provides two comprehensive examples that serve as practical guides for developers: + +1. `sdk-backend-node`: A backend implementation using Node.js. +2. `sdk-frontend/video`: A frontend implementation focusing on video notifications. + +These examples illuminate the application of the Push Protocol in real-world scenarios, making it easier for you to effectively incorporate it into your own projects. + +They are the perfect starting point for any hacker looking to dive into the world of decentralized notifications. Explore, learn, and create with the Push Protocol. Happy hacking! + +# Docs +- [Developer Docs](https://docs.epns.io/developers) +- [Documentation Hub](https://docs.epns.io) + From e812b21665b8006ae4ad0230e0c3f31270fa982a Mon Sep 17 00:00:00 2001 From: Firas Mumtaz <72166289+firascodes@users.noreply.github.com> Date: Thu, 13 Jul 2023 03:36:08 +0530 Subject: [PATCH 3/9] Create Readme.md --- packages/examples/sdk-backend-node/Readme.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/examples/sdk-backend-node/Readme.md diff --git a/packages/examples/sdk-backend-node/Readme.md b/packages/examples/sdk-backend-node/Readme.md new file mode 100644 index 000000000..041d4319a --- /dev/null +++ b/packages/examples/sdk-backend-node/Readme.md @@ -0,0 +1,20 @@ +# SDK Backend Node Example + +This is an example project demonstrating how to implement Push Protocol on the backend using Node.js. +This example is a valuable resource for any developer looking to integrate Push Protocol into their backend services. By exploring the code, you can gain a deeper understanding of how to implement various features of the Push Protocol in a Node.js backend. + + +## Overview + +The `sdk-backend-node` project provides a practical demonstration of how to set up and configure the EPNS on a server, including how to handle notifications and communicate with the blockchain. + +## Getting Started + +To get started with this project: + +1. Clone the `push-sdk` repository. +2. Navigate to the `sdk-backend-node` directory. +3. Install the necessary dependencies. +4. Set up your environment variables based on the provided `.env.sample` file. +5. Run the project. + From b069298c0f367aaf17aa26bfedad4a2f13944aa0 Mon Sep 17 00:00:00 2001 From: Monalisha Mishra <42746736+mishramonalisha76@users.noreply.github.com> Date: Thu, 13 Jul 2023 16:01:13 +0530 Subject: [PATCH 4/9] Feat/notification theme (#524) * fix: adding theme * fix: added theming to notification Item * fix: fixed review issues --- .../demoreact/src/app/NotificationsTest.tsx | 33 +- .../src/lib/components/notification/index.tsx | 297 ++++++++++-------- .../components/notification/theme/index.ts | 104 ++++++ 3 files changed, 301 insertions(+), 133 deletions(-) create mode 100644 packages/uiweb/src/lib/components/notification/theme/index.ts diff --git a/packages/demoreact/src/app/NotificationsTest.tsx b/packages/demoreact/src/app/NotificationsTest.tsx index 336509f46..de905e121 100644 --- a/packages/demoreact/src/app/NotificationsTest.tsx +++ b/packages/demoreact/src/app/NotificationsTest.tsx @@ -5,7 +5,7 @@ import Loader from './components/Loader'; import { DarkIcon, LightIcon } from './components/Icons'; import { Web3Context, EnvContext } from './context'; import * as PushAPI from '@pushprotocol/restapi'; -import { NotificationItem, chainNameType, SubscribedModal } from '@pushprotocol/uiweb'; +import { NotificationItem, chainNameType, SubscribedModal, INotificationItemTheme, notificationBaseTheme, notificationLightTheme } from '@pushprotocol/uiweb'; import { getCAIPAddress } from './helpers'; import sampleNotifications from './data'; @@ -52,8 +52,34 @@ const NotificationsTest = () => { const [theme, setTheme] = useState('dark'); const [viewType, setViewType] = useState('notif'); const [showSubscribe, setShowSubscribe] = useState(false); - - + const customTheme: INotificationItemTheme = {...notificationLightTheme,...{ + borderRadius:{ + ...notificationLightTheme.borderRadius, + modal:'12px', + }, + color:{ + ...notificationLightTheme.color, + channelNameText:'#62626A', + notificationTitleText:'#000', + notificationContentText:'#62626A', + timestamp:'#62626A', + }, + fontWeight:{ + ...notificationLightTheme.fontWeight, + channelNameText:700, + notificationTitleText:700, + notificationContentText:800, + timestamp:400 + }, + fontSize:{ + ...notificationLightTheme.fontSize, + channelNameText:'16px', + notificationTitleText:'16px', + notificationContentText:'16px', + timestamp:'12px' + }, + modalDivider:'none' +}}; const loadNotifications = useCallback(async () => { try { setLoading(true); @@ -171,6 +197,7 @@ const NotificationsTest = () => { image={image} url={url} theme={theme} + customTheme={customTheme} // chainName="ETH_TEST_GOERLI" chainName={blockchain as chainNameType} /> diff --git a/packages/uiweb/src/lib/components/notification/index.tsx b/packages/uiweb/src/lib/components/notification/index.tsx index a0914e3a0..ca65ab0d9 100644 --- a/packages/uiweb/src/lib/components/notification/index.tsx +++ b/packages/uiweb/src/lib/components/notification/index.tsx @@ -1,21 +1,37 @@ -import * as React from "react"; -import * as PropTypes from "prop-types"; -import styled from "styled-components"; - -import IPFSIcon from "../ipfsicon"; -import ImageOverlayComponent from "../overlay"; -import { ParseMarkdownText } from "../parsetext"; -import Loader from "../loader/loader"; -import { extractTimeStamp, convertTimeStamp, MediaHelper } from "../../utilities"; +import * as React from 'react'; +import * as PropTypes from 'prop-types'; +import styled from 'styled-components'; + +import IPFSIcon from '../ipfsicon'; +import ImageOverlayComponent from '../overlay'; +import { ParseMarkdownText } from '../parsetext'; +import Loader from '../loader/loader'; +import { + extractTimeStamp, + convertTimeStamp, + MediaHelper, +} from '../../utilities'; import ActionButton from './styled/ActionButton'; import { useDecrypt, DecryptButton } from './decrypt'; import chainDetails from './chainDetails'; -import LinkSVG from "../../icons/link.svg"; - +import LinkSVG from '../../icons/link.svg'; +import { getCustomTheme, INotificationItemTheme, lightTheme } from './theme'; +export {lightTheme as notificationLightTheme,darkTheme as notificationDarkTheme,baseTheme as notificationBaseTheme,INotificationItemTheme} from './theme'; // ================= Define types -export type chainNameType = "ETH_TEST_GOERLI" | "POLYGON_TEST_MUMBAI" | "ETH_MAINNET" | "POLYGON_MAINNET" | "BSC_MAINNET" | "BSC_TESTNET" | "OPTIMISM_MAINNET" | "OPTIMISM_TESTNET" | "POLYGON_ZK_EVM_TESTNET" | "POLYGON_ZK_EVM_MAINNET" | "THE_GRAPH" | undefined; - +export type chainNameType = + | 'ETH_TEST_GOERLI' + | 'POLYGON_TEST_MUMBAI' + | 'ETH_MAINNET' + | 'POLYGON_MAINNET' + | 'BSC_MAINNET' + | 'BSC_TESTNET' + | 'OPTIMISM_MAINNET' + | 'OPTIMISM_TESTNET' + | 'POLYGON_ZK_EVM_TESTNET' + | 'POLYGON_ZK_EVM_MAINNET' + | 'THE_GRAPH' + | undefined; export type NotificationItemProps = { notificationTitle: string | undefined; @@ -29,16 +45,24 @@ export type NotificationItemProps = { subscribeFn?: () => Promise; isSubscribedFn?: () => Promise; theme: string | undefined; + customTheme?: INotificationItemTheme | undefined; chainName: chainNameType; isSecret?: boolean; - decryptFn?: () => Promise<{ title: string, body: string, cta: string, image: string }>; + decryptFn?: () => Promise<{ + title: string; + body: string; + cta: string; + image: string; + }>; }; - type ContainerDataType = { timestamp?: string; }; +type CustomThemeProps = { + themeObject: INotificationItemTheme; +}; type CTADataType = { cta?: boolean; }; @@ -47,7 +71,7 @@ type MetaDataType = { hidden?: boolean; }; -type MetaInfoType = MetaDataType & { hasLeft: boolean } +type MetaInfoType = MetaDataType & { hasLeft: boolean }; // ================= Define base component export const NotificationItem: React.FC = ({ @@ -63,15 +87,21 @@ export const NotificationItem: React.FC = ({ subscribeFn, //A function for subscribing to the spam channel theme, //for specifying light and dark theme chainName, + customTheme, isSecret, - decryptFn + decryptFn, }) => { const { notificationBody: parsedBody, timeStamp } = extractTimeStamp( - notificationBody || "" + notificationBody || '' ); + const themeObject = getCustomTheme(theme,customTheme!); + const { - notifTitle, notifBody, notifCta, notifImage, + notifTitle, + notifBody, + notifCta, + notifImage, setDecryptedValues, isSecretRevealed, } = useDecrypt({ notificationTitle, parsedBody, cta, image }, isSecret); @@ -80,7 +110,7 @@ export const NotificationItem: React.FC = ({ const isChannelURLValid = MediaHelper.validURL(url); // store the image to be displayed in this state variable - const [imageOverlay, setImageOverlay] = React.useState(""); + const [imageOverlay, setImageOverlay] = React.useState(''); const [subscribeLoading, setSubscribeLoading] = React.useState(false); const [isSubscribed, setIsSubscribed] = React.useState(true); //use this to confirm if this is s @@ -93,23 +123,23 @@ export const NotificationItem: React.FC = ({ const gotToCTA = (e: React.SyntheticEvent) => { e.stopPropagation(); if (!isCtaURLValid) return; - window.open(notifCta, "_blank"); + window.open(notifCta, '_blank'); }; const goToURL = (e: React.SyntheticEvent) => { e.stopPropagation(); if (!isChannelURLValid) return; - window.open(url, "_blank"); + window.open(url, '_blank'); }; /** - * A function which wraps around the function to subscribe a user to a channel - * @returns + * A function which wraps around the function to subscribe a user to a channel + * @returns */ const onSubscribe = async (clickEvent: React.SyntheticEvent) => { clickEvent.preventDefault(); clickEvent.stopPropagation(); - + if (!subscribeFn) return; try { setSubscribeLoading(true); @@ -136,49 +166,48 @@ export const NotificationItem: React.FC = ({ React.useEffect(() => { if (!isSpam || !isSubscribedFn) return; - + isSubscribedFn().then((res: unknown) => { setIsSubscribed(Boolean(res)); - }) + }); + }, [isSubscribedFn, isSpam]); - },[isSubscribedFn, isSpam]); - if (isSubscribed && isSpam) return null; // render return ( - + {/* header that only pops up on small devices */} - - + + - - {app} - + {app} {chainName && chainDetails[chainName] ? ( {chainDetails[chainName].icon} ) : null} - + {/* header that only pops up on small devices */} {/* content of the component */} - + {/* section for media content */} {notifImage && // if its an image then render this (!MediaHelper.isMediaSupportedVideo(notifImage) ? ( setImageOverlay(notifImage || "")} + style={{ cursor: 'pointer' }} + onClick={() => setImageOverlay(notifImage || '')} > @@ -207,24 +236,27 @@ export const NotificationItem: React.FC = ({ {/* section for text content */} - - + + {notifTitle} {/* display link svg if notification has a valid cta url */} - { - isCtaURLValid - ? - CTA link - : - "" - } + {isCtaURLValid ? ( + CTA link + ) : ( + '' + )} - - + + @@ -236,17 +268,19 @@ export const NotificationItem: React.FC = ({ {/* include a channel opt into */} {isSpam && ( - {subscribeLoading ? : "opt-in"} + {subscribeLoading ? : 'opt-in'} )} {/* include a channel opt into */} {isSecret ? ( - - ): null} + + ) : null} - {/* content of the component */} @@ -261,10 +295,10 @@ export const NotificationItem: React.FC = ({ - ): null} - + ) : null} + {timeStamp ? ( - + {convertTimeStamp(timeStamp)} ) : null} @@ -292,35 +326,37 @@ NotificationItem.propTypes = { isSpam: PropTypes.bool, subscribeFn: PropTypes.func, isSubscribedFn: PropTypes.func, - theme: PropTypes.string + theme: PropTypes.string, + customTheme:PropTypes.object }; NotificationItem.defaultProps = { - notificationTitle: "", - notificationBody: "", - cta: "", - app: "", - image: "", - url: "", + notificationTitle: '', + notificationBody: '', + cta: '', + app: '', + image: '', + url: '', isSpam: false, - theme: "light", + theme: 'light', }; // ================= Define styled components // ================= Define styled components -const MD_BREAKPOINT = "50050px"; //set an arbitrarily large number because we no longer use this breakpoint -const SM_BREAKPOINT = "900px"; +const MD_BREAKPOINT = '50050px'; //set an arbitrarily large number because we no longer use this breakpoint +const SM_BREAKPOINT = '900px'; -const ContentSection = styled.div` +const ContentSection = styled.div` display: flex; padding: 15px 16px; - cursor: ${(props) => (props.cta ? "pointer" : "default")}; + cursor: ${(props) => (props.cta ? 'pointer' : 'default')}; - &:hover{ - background: ${(props) => (props.cta ? (props.theme === "light" ? "#e8eaf680" : "#404650") : "none")}; + &:hover { + background: ${(props) => + props.cta ? (props?.themeObject?.color?.contentHoverBackground) : 'none'}; } - + @media (min-width: ${SM_BREAKPOINT}) { align-items: flex-start; flex-direction: row; @@ -343,7 +379,9 @@ const ChainIconSVG = styled.div` width: 28px; height: 28px; - svg, svg image, img { + svg, + svg image, + img { width: 100%; height: 100%; } @@ -366,7 +404,8 @@ const MobileImage = styled.div` } @media (min-width: ${SM_BREAKPOINT}) { - border: 1px solid ${props => props.theme === 'light' ? '#ededed' : '#444'}; + border: 1px solid + ${(props) => (props.theme === 'light' ? '#ededed' : '#444')}; border-radius: 10px; min-width: 220px; width: 220px; @@ -390,7 +429,7 @@ const MobileImage = styled.div` `; const ImageContainer = styled.span` - background: ${(props) => (props.theme === "light" ? "#ededed" : "#444")}; + background: ${(props) => (props.theme === 'light' ? '#ededed' : '#444')}; display: inline-block; margin-right: 10px; border-radius: 5px; @@ -403,24 +442,21 @@ const ImageContainer = styled.span` `; const ChannelDetailsWrapper = styled.div` - display: flex; - flex-direction: column; - flex-grow: 4; + display: flex; + flex-direction: column; + flex-grow: 4; `; -const Container = styled.div` +const Container = styled.div` position: relative; overflow: hidden; - font-family: Strawford, sans-serif; + font-family: ${(props) => props?.themeObject?.fontFamily}; flex: 1; display: flex; flex-wrap: wrap; - border: ${(props) => - props.theme === "light" - ? "1px solid #D9D9D9" - : "1px solid #4A4F67"}; - background: ${(props) => (props.theme === "light" ? "#fff" : "#2F3137")}; - border-radius: 10px; + border: ${(props) => `1px solid ${props?.themeObject?.color?.modalBorder}`}; + background: ${(props) => props?.themeObject?.color?.accentBackground}; + border-radius: ${(props) => props?.themeObject?.borderRadius?.modal}; margin: 1.8rem 0px; justify-content: center; justify-content: space-between; @@ -429,14 +465,14 @@ const Container = styled.div` } `; -const MobileHeader = styled.div` +const MobileHeader = styled.div` display: none; @media (max-width: ${MD_BREAKPOINT}) { display: flex; align-items: center; justify-content: space-between; padding: 12px 10px; - border-bottom: ${(props) => props.theme === "light" ? "1px solid #D9D9D9" : "1px solid #4A4F67"}; + border-bottom: ${(props) => props?.themeObject?.modalDivider}; border-top-left-radius: 10px; border-top-right-radius: 10px; text-align: left; @@ -445,33 +481,33 @@ const MobileHeader = styled.div` const ChannelName = styled.div` cursor: pointer; - &:hover{ + &:hover { text-decoration: underline; } -` +`; -const HeaderButton = styled.div` +const HeaderButton = styled.div` display: flex; justify-content: space-between; align-items: center; - font-size: 15px; - font-weight: 400; - color: ${(props) => (props.theme === "light" ? "#333333" : "#C5CAE9")}; + font-size: ${(props) => props?.themeObject?.fontSize?.channelNameText}; + font-weight: ${(props) => props?.themeObject?.fontWeight?.channelNameText}; + color: ${(props) => props?.themeObject?.color?.channelNameText}; `; -const ChannelTitle = styled.div` +const ChannelTitle = styled.div` width: fit-content; display: flex; align-items: center; text-align: left; margin-bottom: 8px; - - &:hover{ - text-decoration: ${(props) => (props.cta ? "underline" : "none")}; + + &:hover { + text-decoration: ${(props) => (props.cta ? 'underline' : 'none')}; } - + @media (max-width: ${MD_BREAKPOINT}) { - color: ${(props) => (props.theme === "light" ? "#333333" : "#C5CAE9")}; + color: ${(props) => props?.themeObject?.color?.notificationTitleText}; } @media (max-width: ${SM_BREAKPOINT}) { @@ -479,38 +515,39 @@ const ChannelTitle = styled.div` } `; -const ChannelTitleText = styled.div` - font-size: 22px; - font-weight: 400; -` - -const ChannelDesc = styled.div` +const ChannelTitleText = styled.div` + font-size: ${(props) => props?.themeObject?.fontSize?.notificationTitleText}; + font-weight: ${(props) => + props?.themeObject?.fontWeight?.notificationTitleText}; +`; +const ChannelDesc = styled.div` line-height: 20px; flex: 1; display: flex; - font-size: 16px; - color: rgba(0, 0, 0, 0.75); - font-weight: 400; + font-size: ${(props) => + props?.themeObject?.fontSize?.notificationContentText}; + color: ${(props) => props?.themeObject?.color?.notificationContentText}; + font-weight: ${(props) => + props?.themeObject?.fontWeight?.notificationContentText}; flex-direction: column; `; -const ChannelDescLabel = styled.label` - cursor: ${(props) => (props.cta ? "pointer" : "default")}; - color: ${(props) => (props.theme === "light" ? "#333333" : "#C5CAE9")}; +const ChannelDescLabel = styled.label` + cursor: ${(props) => (props.cta ? 'pointer' : 'default')}; + color: ${(props) => props?.themeObject?.color?.notificationContentText}; flex: 1; margin: 0px; text-align: left; `; - const ChannelMetaInfo = styled.div` - display: ${(props) => (props.hidden ? "none" : "flex")}; + display: ${(props) => (props.hidden ? 'none' : 'flex')}; flex-direction: row; - justify-content: ${(props) => (props.hasLeft ? "space-between" : "end")}; + justify-content: ${(props) => (props.hasLeft ? 'space-between' : 'end')}; `; const ChannelMetaSection = styled.div` - display: ${(props) => (props.hidden ? "none" : "flex")}; + display: ${(props) => (props.hidden ? 'none' : 'flex')}; align-items: center; `; @@ -522,8 +559,8 @@ const ChannelMetaInfoRight = styled(ChannelMetaSection)` justify-content: end; `; -const TimestampLabel = styled.label` - color: #808080; +const TimestampLabel = styled.label` + color: ${(props) => props?.themeObject?.color?.timestamp}; border-radius: 0; border-top-left-radius: 6px; border-bottom-right-radius: 10px; @@ -531,8 +568,8 @@ const TimestampLabel = styled.label` border-bottom: 0; margin-bottom: -1px; margin-right: -1px; - font-weight: 600; - font-size: 10px; + font-weight: ${(props) => props?.themeObject?.fontWeight?.timestamp}; + font-size: ${(props) => props?.themeObject?.fontSize?.timestamp}; padding: 6px 10px 6px 0px; `; @@ -540,10 +577,10 @@ const SecretIconContainer = styled.div` margin: 6px; `; -const SecretIcon = styled.div` +const SecretIcon = styled.div` width: 12px; height: 12px; - + border-radius: 50%; background: linear-gradient( 135deg, @@ -551,7 +588,7 @@ const SecretIcon = styled.div` #674c9f 49.89%, #35c5f3 87.5% ); -` +`; const ButtonGroupContainer = styled.div` display: flex; @@ -562,4 +599,4 @@ const ButtonGroupContainer = styled.div` const ButtonGroup = styled.div` display: flex; gap: 20px; -`; \ No newline at end of file +`; diff --git a/packages/uiweb/src/lib/components/notification/theme/index.ts b/packages/uiweb/src/lib/components/notification/theme/index.ts new file mode 100644 index 000000000..e54c3bf61 --- /dev/null +++ b/packages/uiweb/src/lib/components/notification/theme/index.ts @@ -0,0 +1,104 @@ +//theme type +interface IBorderRadius { + modal?: string; + optInButton?: string; +} +interface IColor { + accentBackground?: string; + contentHoverBackground?:string; + channelNameText?: string; + notificationTitleText?: string; + notificationContentText?: string; + timestamp?: string; + optInButtonText?: string; + optInButtonBackground?: string; + modalBorder?:string; +} + +interface IFont { + channelNameText?: string; + notificationTitleText?: string; + notificationContentText?: string; + timestamp?: string; + optInButtonText?: string; +} +interface IFontWeight { + channelNameText?: number; + notificationTitleText?: number; + notificationContentText?: number; + timestamp?: number; + optInButtonText?: number; +} +export interface INotificationItemTheme { + borderRadius?: IBorderRadius; + + color?: IColor; + + fontSize?: IFont; + + fontWeight?: IFontWeight; + + fontFamily?: string; + + modalDivider?: string; +} + +//base theme object + +export const baseTheme: INotificationItemTheme = { + borderRadius: { + modal: '10px', + optInButton: '3px', + }, + fontWeight: { + channelNameText: 400, + notificationTitleText: 400, + notificationContentText: 400, + timestamp: 600, + optInButtonText: 500, + }, + fontSize: { + channelNameText: '15px', + notificationTitleText: '22px', + notificationContentText: '16px', + timestamp: '10px', + optInButtonText: 'unset', + }, + fontFamily: 'Strawford, sans-serif', +}; +//light theme object +export const lightTheme: INotificationItemTheme = { + ...baseTheme, + color:{ + accentBackground: '#fff', + contentHoverBackground:'#e8eaf680', + channelNameText:'#333333', + notificationTitleText:'#333333', + notificationContentText:'#333333', + timestamp:'#808080', + optInButtonText:'#fff', + optInButtonBackground:'rgb(226, 8, 128)', + modalBorder:'#D9D9D9' + }, + modalDivider:'1px solid #D9D9D9' +}; +//dark theme object +export const darkTheme: INotificationItemTheme = { + ...baseTheme, + color:{ + accentBackground: '#2F3137', + channelNameText:'#C5CAE9', + contentHoverBackground:'#404650', + notificationTitleText:'#C5CAE9', + notificationContentText:'#C5CAE9', + timestamp:'#808080', + optInButtonText:'#fff', + optInButtonBackground:'rgb(226, 8, 128)', + modalBorder:'#4A4F67' + }, + modalDivider:'1px solid #4A4F67' +}; +//function to return final theme object +export const getCustomTheme = (theme:string | undefined,customTheme:INotificationItemTheme) => { + return Object.assign({}, theme==='dark'?darkTheme:lightTheme, customTheme); +} \ No newline at end of file From e1286074a9b8c0844abb537dbfdec153d0ca78d3 Mon Sep 17 00:00:00 2001 From: Firas Mumtaz <72166289+firascodes@users.noreply.github.com> Date: Fri, 14 Jul 2023 13:28:37 +0530 Subject: [PATCH 5/9] Update Readme.md --- packages/examples/Readme.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/examples/Readme.md b/packages/examples/Readme.md index 09b967e62..140997869 100644 --- a/packages/examples/Readme.md +++ b/packages/examples/Readme.md @@ -1,4 +1,18 @@ +

+ + + + + + +

+ +

+ Push Protocol is a web3 communication network, enabling cross-chain notifications, messaging, video, and NFT chat for dapps, wallets, and services.🚀 +

+ # Welcome to Push SDK Examples! +This repository houses various practical examples that illustrate how to use the Push SDK effectively to enhance your applications with advanced web3 communication functionalities. ## One-Stop Solution for Understanding the Implementation of Push Protocol's SDK @@ -12,6 +26,6 @@ These examples illuminate the application of the Push Protocol in real-world sce They are the perfect starting point for any hacker looking to dive into the world of decentralized notifications. Explore, learn, and create with the Push Protocol. Happy hacking! # Docs -- [Developer Docs](https://docs.epns.io/developers) -- [Documentation Hub](https://docs.epns.io) +- [Developer Docs](https://docs.push.org/developers) +- [Documentation Hub](https://docs.push.org) From 1426024574e0030d9dbfe07b668bfd315798f049 Mon Sep 17 00:00:00 2001 From: Firas Mumtaz <72166289+firascodes@users.noreply.github.com> Date: Fri, 14 Jul 2023 13:34:42 +0530 Subject: [PATCH 6/9] Update Readme.md --- packages/examples/sdk-backend-node/Readme.md | 38 ++++++++++++++------ 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/examples/sdk-backend-node/Readme.md b/packages/examples/sdk-backend-node/Readme.md index 041d4319a..5d2f632d8 100644 --- a/packages/examples/sdk-backend-node/Readme.md +++ b/packages/examples/sdk-backend-node/Readme.md @@ -1,20 +1,38 @@ # SDK Backend Node Example -This is an example project demonstrating how to implement Push Protocol on the backend using Node.js. -This example is a valuable resource for any developer looking to integrate Push Protocol into their backend services. By exploring the code, you can gain a deeper understanding of how to implement various features of the Push Protocol in a Node.js backend. - +Welcome to the SDK Backend Node Example project, a hands-on guide demonstrating how to leverage the power of Push Protocol in a backend environment using Node.js. This resource is an invaluable companion for developers keen to integrate Push Protocol into their backend services. Dive into the code to gain a comprehensive understanding of how to deploy various features of the Push Protocol in a Node.js backend. ## Overview -The `sdk-backend-node` project provides a practical demonstration of how to set up and configure the EPNS on a server, including how to handle notifications and communicate with the blockchain. +The `sdk-backend-node` project offers a practical tutorial on how to set up and configure Push Protocol on a server, including guidance on managing notifications and interfacing with the blockchain. This includes essential examples related to: + +- Push Notifications +- Push Chat +- Push NFT Chat +- Push Video + +Through these examples, you'll see how these features can be successfully implemented and integrated using Push Protocol. ## Getting Started -To get started with this project: +Embark on your journey with this project by cloning the repository and installing the dependencies: + +```bash +git clone https://github.com/ethereum-push-notification-service/sdk.git +cd sdk +yarn install +``` +***Note*** - We are using `yarn` and **strongly** advise to use yarn 1.x to avoid any NPM issues. + +## Setting up the SDK-Backend-Node +1. Navigate to the `sdk-backend-node` directory. +2. Set up your environment variables by creating a `.env` file based on the provided `.env.sample` file. -1. Clone the `push-sdk` repository. -2. Navigate to the `sdk-backend-node` directory. -3. Install the necessary dependencies. -4. Set up your environment variables based on the provided `.env.sample` file. -5. Run the project. +## Running the SDK-Backend-Node +### By GUI (preferred) +1. Click on the `NX console` extension icon in the VSCode sidebar. +2. Click on the `serve` target execute icon under `examples-sdk-backend-node` +### By CLI +1. Navigate to the root level of push-sdk repository. +2. Run `yarn nx serve examples-sdk-backend-node` From 93a8fd8b41831ab61931336044a8f66cb9453edd Mon Sep 17 00:00:00 2001 From: Monalisha Mishra <42746736+mishramonalisha76@users.noreply.github.com> Date: Fri, 14 Jul 2023 15:14:35 +0530 Subject: [PATCH 7/9] feat: chat widget component (#386) * feat: chat widget component * refactor: pagination in sidebar * refactor: lint issues fixed * fix: added condition for filtereing group chats * fix: socket changes added * fix: fixe build issues * fix: changed lowercase to actual account * fix: fixed caip issue * fix: fixed css for smaller chats * fix: added unread file and gif msg * fix: fixed all icons * fix: fixed bugs * fix: fixed minor bugs * fix: added rule for import * fix: fixed minor type bugs * fix: fixed minor bugs * fix: changes widget nam * fix: fixed opt-in * fix: create mainContext for chat and notification (#460) * fix: create maincontext for chat and notification * fix: changed the name of the context * fix: fixed issues --------- Co-authored-by: Abhishek * fix: solved lint errors * fix: change socket name * fix: fixed a bug * fix: minor ui fixes * fix: fixed socket bug * fix: added encryption msg * fix: added msg for encrypted text * fix: new Message UI (#461) * fix: new Message UI * fix: new messages UI fixed and also added other fixes" * fix: minor fixes --------- Co-authored-by: Monalisha Mishra * fix: refactored code * Chat UI fixes (#464) * fix: chat UI fixed for UD * fix: fixed minor bugs --------- Co-authored-by: Monalisha Mishra * Chat UI fixes (#468) * fix: chat UI fixed for UD * fix: fixed minor bugs * fix: code refactoring --------- Co-authored-by: abhishek-01k * fix: fix all import issues * fix: fixed scrollbar * fix: fixed pagination bug * fix: lint issues * fix: new Tab Design (#470) * fix: new Tab Design * fix: fixed the height of unread message * fix: fixed css --------- Co-authored-by: Monalisha Mishra * fix: fixed linting * fix: new chat widget design when a new message appear (#476) * fix: new chat widget design when a new message appear * fix: new chat widget design css fix * fix: lint issues fixed --------- Co-authored-by: Monalisha Mishra * fix: fixed typebr bug * fix: fixed minor bugs * fix: fixed domain resolve * Fixed issue for search in chat (#480) * fix: chat search issue resolved for UD * fix: fixed code --------- Co-authored-by: Monalisha Mishra * fix: scrollbar issue fixed (#487) * fix: scrollbar issue fixed * fix: new scrollbar issue resolved * fix: fixed a minor padding --------- Co-authored-by: Monalisha Mishra * fix: fixed notification layout * fix: chat UI fixes (#486) * fix: chat UI fixes * fix: fixed minor bugs --------- Co-authored-by: Monalisha Mishra * fix: responsiveness for chatsnap is fixed (#493) * fix: responsiveness for chatsnap is fixed * fix: fixed tab font --------- Co-authored-by: Monalisha Mishra * fix: fixed domain resolve * fix: minors bug fixes --------- Co-authored-by: Abhishek <77395788+abhishek-01k@users.noreply.github.com> Co-authored-by: Abhishek Co-authored-by: abhishek-01k --- packages/demoreact/src/app/ChatWidgetTest.tsx | 45 + .../demoreact/src/app/NotificationsTest.tsx | 58 +- packages/demoreact/src/app/app.tsx | 4 +- .../demoreact/src/app/context/envContext.ts | 2 +- packages/restapi/README.md | 43 + packages/restapi/yarn.lock | 605 ++++++- packages/uiweb/.eslintrc.json | 4 +- packages/uiweb/package.json | 14 +- .../ChatAndNotification.tsx | 230 +++ .../ChatAndNotificationWidget.tsx | 62 + .../MinimisedModalHeader.tsx | 290 ++++ .../components/chatAndNotification/index.ts | 2 + .../chatAndNotification/modal/Modal.tsx | 40 + .../chatAndNotification/modal/index.ts | 1 + .../modal/messageBox/MessageBox.tsx | 516 ++++++ .../modal/messageBox/typebar/Typebar.tsx | 340 ++++ .../modal/sidebar/Search.tsx | 180 ++ .../modal/sidebar/Sidebar.tsx | 460 +++++ .../modal/sidebar/SidebarPlaceholder.tsx | 62 + .../modal/sidebar/chatSidebar/ChatList.tsx | 25 + .../modal/sidebar/chatSidebar/ChatSnap.tsx | 188 ++ .../sidebar/chatSidebar/ChatsFeedList.tsx | 120 ++ .../sidebar/chatSidebar/RequestsFeedList.tsx | 113 ++ .../InboxNotificationFeedList.tsx | 171 ++ .../NotificationFeedList.tsx | 89 + .../SpamNotificationFeedList.tsx | 133 ++ packages/uiweb/src/lib/components/index.ts | 3 +- .../components/notification/chainDetails.tsx | 76 +- .../src/lib/components/notification/index.tsx | 198 ++- .../lib/components/parsetext/customParser.tsx | 2 +- .../components/parsetext/defaultPatterns.ts | 2 +- .../src/lib/components/parsetext/index.tsx | 2 +- .../parsetext/lib/TextExtraction.ts | 2 +- .../src/lib/components/reusables/Spinner.tsx | 36 + .../src/lib/components/reusables/Tooltip.tsx | 136 ++ .../src/lib/components/reusables/index.tsx | 3 + .../components/reusables/sharedStyling.tsx | 165 ++ .../{chat => supportChat}/AddressInfo.tsx | 6 +- .../{chat => supportChat}/ChatInput.tsx | 17 +- .../{chat => supportChat}/Chats.tsx | 8 +- .../{chat => supportChat}/Modal.tsx | 31 +- .../{chat => supportChat}/ModalHeader.tsx | 21 +- .../{chat => supportChat}/index.css | 0 .../{chat => supportChat}/index.tsx | 36 +- .../{chat => supportChat/spinner}/Spinner.tsx | 6 +- .../{chat => supportChat/toaster}/Toaster.tsx | 10 +- .../src/lib/components/tooltip/index.tsx | 1 - packages/uiweb/src/lib/config/constants.ts | 77 + packages/uiweb/src/lib/config/globals.ts | 21 + packages/uiweb/src/lib/config/index.ts | 3 +- packages/uiweb/src/lib/config/themisation.tsx | 2 +- .../chat/chatMainStateContext.tsx | 102 ++ .../chatAndNotificationMainContext.tsx | 49 + .../chatAndNotificationPropsContext.ts | 5 + .../notificationMainStateContext.tsx | 101 ++ .../src/lib/context/chatMainStateContext.ts | 5 - .../uiweb/src/lib/context/chatPropsContext.ts | 5 - packages/uiweb/src/lib/context/index.ts | 19 +- .../supportChatMainStateContext.ts | 5 + .../supportChat/supportChatPropsContext.ts | 5 + packages/uiweb/src/lib/helpers/address.ts | 8 +- .../uiweb/src/lib/helpers/{ => chat}/chat.ts | 68 +- packages/uiweb/src/lib/helpers/chat/index.ts | 6 + .../src/lib/helpers/chat/localStorage.ts | 25 + packages/uiweb/src/lib/helpers/chat/search.ts | 119 ++ packages/uiweb/src/lib/helpers/chat/time.ts | 12 + packages/uiweb/src/lib/helpers/chat/user.ts | 33 + .../uiweb/src/lib/helpers/chat/utility.ts | 15 + packages/uiweb/src/lib/helpers/index.ts | 5 +- .../src/lib/helpers/notification/address.ts | 7 + .../notification/formatNotification.ts | 21 + .../src/lib/helpers/notification/index.ts | 2 + packages/uiweb/src/lib/helpers/udResolver.ts | 23 + packages/uiweb/src/lib/hooks/chat/index.ts | 9 + .../lib/hooks/chat/useApproveChatRequest.ts | 42 + .../uiweb/src/lib/hooks/chat/useFetchChat.ts | 47 + .../uiweb/src/lib/hooks/chat/useFetchChats.ts | 60 + .../hooks/chat/useFetchConversationHash.ts | 40 + .../lib/hooks/chat/useFetchHistoryMessages.ts | 70 + .../src/lib/hooks/chat/useFetchRequests.ts | 58 + .../src/lib/hooks/chat/useGetChatProfile.ts | 32 + .../src/lib/hooks/chat/useIsInViewport.ts | 22 + .../src/lib/hooks/chat/usePushSendMessage.ts | 83 + .../lib/hooks/chatAndNotification/index.ts | 1 + .../useChatNotificationSocket.ts | 262 +++ packages/uiweb/src/lib/hooks/index.ts | 9 +- .../src/lib/hooks/notifications/index.ts | 3 + .../notifications/useFetchNotification.ts | 58 + .../useFetchUserSubscriptions.ts | 45 + .../notifications/useOnSubscribeToChannel.ts | 59 + packages/uiweb/src/lib/hooks/useClickAway.ts | 3 +- .../src/lib/hooks/useDeviceWidthCheck.ts | 25 + .../uiweb/src/lib/hooks/useDivOffsetWidth.ts | 36 + .../uiweb/src/lib/hooks/useResolveWeb3Name.ts | 77 + packages/uiweb/src/lib/icons/AngleArrow.tsx | 10 + packages/uiweb/src/lib/icons/Attachment.tsx | 21 + packages/uiweb/src/lib/icons/BSCSvg.tsx | 11 + packages/uiweb/src/lib/icons/Back.tsx | 9 + packages/uiweb/src/lib/icons/ChatIcon.tsx | 10 + packages/uiweb/src/lib/icons/CheckCircle.tsx | 10 + packages/uiweb/src/lib/icons/Close.tsx | 13 + .../src/lib/icons/{chat => }/CopySvg.tsx | 0 packages/uiweb/src/lib/icons/Emoji.tsx | 15 + packages/uiweb/src/lib/icons/Encryption.tsx | 13 + packages/uiweb/src/lib/icons/EthereumSvg.tsx | 15 + packages/uiweb/src/lib/icons/Gif.tsx | 12 + .../src/lib/icons/{chat => }/HandWaveSvg.tsx | 0 packages/uiweb/src/lib/icons/Link.tsx | 11 + packages/uiweb/src/lib/icons/Maximize.tsx | 10 + packages/uiweb/src/lib/icons/Minimize.tsx | 11 + packages/uiweb/src/lib/icons/NewChat.tsx | 24 + packages/uiweb/src/lib/icons/NewMessage.tsx | 15 + packages/uiweb/src/lib/icons/NoEncryption.tsx | 14 + packages/uiweb/src/lib/icons/OptimismSvg.tsx | 21 + packages/uiweb/src/lib/icons/PolygonSvg.tsx | 20 + .../uiweb/src/lib/icons/PolygonzkevmSvg.tsx | 25 + packages/uiweb/src/lib/icons/Search.tsx | 19 + packages/uiweb/src/lib/icons/Send.tsx | 12 + .../src/lib/icons/{chat => }/SendIconSvg.tsx | 0 packages/uiweb/src/lib/icons/Spam.tsx | 10 + packages/uiweb/src/lib/icons/SponserPush.tsx | 51 + packages/uiweb/src/lib/icons/TheGraphSvg.tsx | 22 + packages/uiweb/src/lib/icons/bsc.svg | 4 - .../uiweb/src/lib/icons/chat/attachment.svg | 3 - .../uiweb/src/lib/icons/chat/chatIcon.svg | 3 - packages/uiweb/src/lib/icons/chat/copy.svg | 4 - packages/uiweb/src/lib/icons/close.svg | 4 - packages/uiweb/src/lib/icons/error.svg | 3 - packages/uiweb/src/lib/icons/ethereum.svg | 9 - packages/uiweb/src/lib/icons/link.svg | 4 - packages/uiweb/src/lib/icons/optimism.svg | 12 - packages/uiweb/src/lib/icons/polygon.svg | 11 - packages/uiweb/src/lib/icons/polygonzkevm.svg | 15 - .../src/lib/icons/{chat => }/pushIcon.svg | 0 .../uiweb/src/lib/icons/{chat => }/smiley.svg | 0 .../src/lib/icons/{chat => }/sponsorPush.svg | 0 .../minimize.svg => supportChatMinimize.svg} | 0 packages/uiweb/src/lib/icons/thegraph.svg | 11 - packages/uiweb/src/lib/index.ts | 2 +- packages/uiweb/src/lib/types/index.ts | 57 +- .../uiweb/src/lib/utilities/formatType.ts | 4 + packages/uiweb/src/lib/utilities/index.ts | 3 +- packages/uiweb/tsconfig.json | 1 + packages/uiweb/tsconfig.lib.json | 2 +- packages/uiweb/yarn.lock | 1546 ++++++++++++++++- 145 files changed, 8055 insertions(+), 389 deletions(-) create mode 100644 packages/demoreact/src/app/ChatWidgetTest.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotification.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotificationWidget.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/MinimisedModalHeader.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/index.ts create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/Modal.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/index.ts create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/messageBox/MessageBox.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/messageBox/typebar/Typebar.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/Search.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/Sidebar.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/SidebarPlaceholder.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatList.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatSnap.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatsFeedList.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/RequestsFeedList.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/InboxNotificationFeedList.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/NotificationFeedList.tsx create mode 100644 packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/SpamNotificationFeedList.tsx create mode 100644 packages/uiweb/src/lib/components/reusables/Spinner.tsx create mode 100644 packages/uiweb/src/lib/components/reusables/Tooltip.tsx create mode 100644 packages/uiweb/src/lib/components/reusables/index.tsx create mode 100644 packages/uiweb/src/lib/components/reusables/sharedStyling.tsx rename packages/uiweb/src/lib/components/{chat => supportChat}/AddressInfo.tsx (93%) rename packages/uiweb/src/lib/components/{chat => supportChat}/ChatInput.tsx (92%) rename packages/uiweb/src/lib/components/{chat => supportChat}/Chats.tsx (95%) rename packages/uiweb/src/lib/components/{chat => supportChat}/Modal.tsx (90%) rename packages/uiweb/src/lib/components/{chat => supportChat}/ModalHeader.tsx (68%) rename packages/uiweb/src/lib/components/{chat => supportChat}/index.css (100%) rename packages/uiweb/src/lib/components/{chat => supportChat}/index.tsx (78%) rename packages/uiweb/src/lib/components/{chat => supportChat/spinner}/Spinner.tsx (81%) rename packages/uiweb/src/lib/components/{chat => supportChat/toaster}/Toaster.tsx (81%) create mode 100644 packages/uiweb/src/lib/config/globals.ts create mode 100644 packages/uiweb/src/lib/context/chatAndNotification/chat/chatMainStateContext.tsx create mode 100644 packages/uiweb/src/lib/context/chatAndNotification/chatAndNotificationMainContext.tsx create mode 100644 packages/uiweb/src/lib/context/chatAndNotification/chatAndNotificationPropsContext.ts create mode 100644 packages/uiweb/src/lib/context/chatAndNotification/notifcation/notificationMainStateContext.tsx delete mode 100644 packages/uiweb/src/lib/context/chatMainStateContext.ts delete mode 100644 packages/uiweb/src/lib/context/chatPropsContext.ts create mode 100644 packages/uiweb/src/lib/context/supportChat/supportChatMainStateContext.ts create mode 100644 packages/uiweb/src/lib/context/supportChat/supportChatPropsContext.ts rename packages/uiweb/src/lib/helpers/{ => chat}/chat.ts (63%) create mode 100644 packages/uiweb/src/lib/helpers/chat/index.ts create mode 100644 packages/uiweb/src/lib/helpers/chat/localStorage.ts create mode 100644 packages/uiweb/src/lib/helpers/chat/search.ts create mode 100644 packages/uiweb/src/lib/helpers/chat/time.ts create mode 100644 packages/uiweb/src/lib/helpers/chat/user.ts create mode 100644 packages/uiweb/src/lib/helpers/chat/utility.ts create mode 100644 packages/uiweb/src/lib/helpers/notification/address.ts create mode 100644 packages/uiweb/src/lib/helpers/notification/formatNotification.ts create mode 100644 packages/uiweb/src/lib/helpers/notification/index.ts create mode 100644 packages/uiweb/src/lib/helpers/udResolver.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/index.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/useApproveChatRequest.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/useFetchChat.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/useFetchChats.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/useFetchConversationHash.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/useFetchHistoryMessages.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/useFetchRequests.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/useGetChatProfile.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/useIsInViewport.ts create mode 100644 packages/uiweb/src/lib/hooks/chat/usePushSendMessage.ts create mode 100644 packages/uiweb/src/lib/hooks/chatAndNotification/index.ts create mode 100644 packages/uiweb/src/lib/hooks/chatAndNotification/useChatNotificationSocket.ts create mode 100644 packages/uiweb/src/lib/hooks/notifications/index.ts create mode 100644 packages/uiweb/src/lib/hooks/notifications/useFetchNotification.ts create mode 100644 packages/uiweb/src/lib/hooks/notifications/useFetchUserSubscriptions.ts create mode 100644 packages/uiweb/src/lib/hooks/notifications/useOnSubscribeToChannel.ts create mode 100644 packages/uiweb/src/lib/hooks/useDeviceWidthCheck.ts create mode 100644 packages/uiweb/src/lib/hooks/useDivOffsetWidth.ts create mode 100644 packages/uiweb/src/lib/hooks/useResolveWeb3Name.ts create mode 100644 packages/uiweb/src/lib/icons/AngleArrow.tsx create mode 100644 packages/uiweb/src/lib/icons/Attachment.tsx create mode 100644 packages/uiweb/src/lib/icons/BSCSvg.tsx create mode 100644 packages/uiweb/src/lib/icons/Back.tsx create mode 100644 packages/uiweb/src/lib/icons/ChatIcon.tsx create mode 100644 packages/uiweb/src/lib/icons/CheckCircle.tsx create mode 100644 packages/uiweb/src/lib/icons/Close.tsx rename packages/uiweb/src/lib/icons/{chat => }/CopySvg.tsx (100%) create mode 100644 packages/uiweb/src/lib/icons/Emoji.tsx create mode 100644 packages/uiweb/src/lib/icons/Encryption.tsx create mode 100644 packages/uiweb/src/lib/icons/EthereumSvg.tsx create mode 100644 packages/uiweb/src/lib/icons/Gif.tsx rename packages/uiweb/src/lib/icons/{chat => }/HandWaveSvg.tsx (100%) create mode 100644 packages/uiweb/src/lib/icons/Link.tsx create mode 100644 packages/uiweb/src/lib/icons/Maximize.tsx create mode 100644 packages/uiweb/src/lib/icons/Minimize.tsx create mode 100644 packages/uiweb/src/lib/icons/NewChat.tsx create mode 100644 packages/uiweb/src/lib/icons/NewMessage.tsx create mode 100644 packages/uiweb/src/lib/icons/NoEncryption.tsx create mode 100644 packages/uiweb/src/lib/icons/OptimismSvg.tsx create mode 100644 packages/uiweb/src/lib/icons/PolygonSvg.tsx create mode 100644 packages/uiweb/src/lib/icons/PolygonzkevmSvg.tsx create mode 100644 packages/uiweb/src/lib/icons/Search.tsx create mode 100644 packages/uiweb/src/lib/icons/Send.tsx rename packages/uiweb/src/lib/icons/{chat => }/SendIconSvg.tsx (100%) create mode 100644 packages/uiweb/src/lib/icons/Spam.tsx create mode 100644 packages/uiweb/src/lib/icons/SponserPush.tsx create mode 100644 packages/uiweb/src/lib/icons/TheGraphSvg.tsx delete mode 100644 packages/uiweb/src/lib/icons/bsc.svg delete mode 100644 packages/uiweb/src/lib/icons/chat/attachment.svg delete mode 100644 packages/uiweb/src/lib/icons/chat/chatIcon.svg delete mode 100644 packages/uiweb/src/lib/icons/chat/copy.svg delete mode 100644 packages/uiweb/src/lib/icons/close.svg delete mode 100644 packages/uiweb/src/lib/icons/error.svg delete mode 100644 packages/uiweb/src/lib/icons/ethereum.svg delete mode 100644 packages/uiweb/src/lib/icons/link.svg delete mode 100644 packages/uiweb/src/lib/icons/optimism.svg delete mode 100644 packages/uiweb/src/lib/icons/polygon.svg delete mode 100644 packages/uiweb/src/lib/icons/polygonzkevm.svg rename packages/uiweb/src/lib/icons/{chat => }/pushIcon.svg (100%) rename packages/uiweb/src/lib/icons/{chat => }/smiley.svg (100%) rename packages/uiweb/src/lib/icons/{chat => }/sponsorPush.svg (100%) rename packages/uiweb/src/lib/icons/{chat/minimize.svg => supportChatMinimize.svg} (100%) delete mode 100644 packages/uiweb/src/lib/icons/thegraph.svg create mode 100644 packages/uiweb/src/lib/utilities/formatType.ts diff --git a/packages/demoreact/src/app/ChatWidgetTest.tsx b/packages/demoreact/src/app/ChatWidgetTest.tsx new file mode 100644 index 000000000..31f4369e9 --- /dev/null +++ b/packages/demoreact/src/app/ChatWidgetTest.tsx @@ -0,0 +1,45 @@ +import React, { useContext, useEffect, useState } from 'react'; +import { ChatAndNotificationWidget, PUSH_TABS } from '@pushprotocol/uiweb'; +import { EnvContext, Web3Context } from './context'; +import * as PushAPI from '@pushprotocol/restapi'; +import { IUser } from '@pushprotocol/restapi'; + + + + +export const ChatWidgetTest = () => { + + const { account, library } = useContext(Web3Context); + const librarySigner = library.getSigner(); + const [pvtKey,setPvtKey] = useState(''); + const {env} = useContext(EnvContext); + + useEffect(()=>{ + (async()=>{ + const user = await PushAPI.user.get({ account: account, env }); + const pvtkey = null; + console.log(user) + if (user?.encryptedPrivateKey) { + const response = await PushAPI.chat.decryptPGPKey({ + encryptedPGPPrivateKey: (user as IUser).encryptedPrivateKey, + account: account, + signer: librarySigner, + env, + toUpgrade: true, + }); + setPvtKey(response) + } + })(); + + },[account,env]) + return ( + + ); +}; diff --git a/packages/demoreact/src/app/NotificationsTest.tsx b/packages/demoreact/src/app/NotificationsTest.tsx index de905e121..26eef90ec 100644 --- a/packages/demoreact/src/app/NotificationsTest.tsx +++ b/packages/demoreact/src/app/NotificationsTest.tsx @@ -52,34 +52,34 @@ const NotificationsTest = () => { const [theme, setTheme] = useState('dark'); const [viewType, setViewType] = useState('notif'); const [showSubscribe, setShowSubscribe] = useState(false); - const customTheme: INotificationItemTheme = {...notificationLightTheme,...{ - borderRadius:{ - ...notificationLightTheme.borderRadius, - modal:'12px', - }, - color:{ - ...notificationLightTheme.color, - channelNameText:'#62626A', - notificationTitleText:'#000', - notificationContentText:'#62626A', - timestamp:'#62626A', - }, - fontWeight:{ - ...notificationLightTheme.fontWeight, - channelNameText:700, - notificationTitleText:700, - notificationContentText:800, - timestamp:400 - }, - fontSize:{ - ...notificationLightTheme.fontSize, - channelNameText:'16px', - notificationTitleText:'16px', - notificationContentText:'16px', - timestamp:'12px' - }, - modalDivider:'none' -}}; +// const customTheme: INotificationItemTheme = {...notificationLightTheme,...{ +// borderRadius:{ +// ...notificationLightTheme.borderRadius, +// modal:'12px', +// }, +// color:{ +// ...notificationLightTheme.color, +// channelNameText:'#62626A', +// notificationTitleText:'#000', +// notificationContentText:'#62626A', +// timestamp:'#62626A', +// }, +// fontWeight:{ +// ...notificationLightTheme.fontWeight, +// channelNameText:700, +// notificationTitleText:700, +// notificationContentText:800, +// timestamp:400 +// }, +// fontSize:{ +// ...notificationLightTheme.fontSize, +// channelNameText:'16px', +// notificationTitleText:'16px', +// notificationContentText:'16px', +// timestamp:'12px' +// }, +// modalDivider:'none' +// }}; const loadNotifications = useCallback(async () => { try { setLoading(true); @@ -197,7 +197,7 @@ const NotificationsTest = () => { image={image} url={url} theme={theme} - customTheme={customTheme} + // customTheme={customTheme} // chainName="ETH_TEST_GOERLI" chainName={blockchain as chainNameType} /> diff --git a/packages/demoreact/src/app/app.tsx b/packages/demoreact/src/app/app.tsx index 0925ebcfb..2615f2bdc 100644 --- a/packages/demoreact/src/app/app.tsx +++ b/packages/demoreact/src/app/app.tsx @@ -34,6 +34,7 @@ import AuthUpdateUserTest from './ChatTest/AuthUpdateUser'; import UpdateUserProfile from './ChatTest/UpdateUserProfile'; import { Buffer } from 'buffer'; import { ENV } from './helpers'; +import { ChatWidgetTest } from './ChatWidgetTest'; window.Buffer = window.Buffer || Buffer; @@ -248,7 +249,8 @@ export function App() { } /> } /> - + {/* */} + ) : null} diff --git a/packages/demoreact/src/app/context/envContext.ts b/packages/demoreact/src/app/context/envContext.ts index 1612f0418..242a5d11f 100644 --- a/packages/demoreact/src/app/context/envContext.ts +++ b/packages/demoreact/src/app/context/envContext.ts @@ -2,4 +2,4 @@ import { createContext } from 'react' const EnvContext = createContext({}); -export default EnvContext; \ No newline at end of file +export default EnvContext; \ No newline at end of file diff --git a/packages/restapi/README.md b/packages/restapi/README.md index 9105d6f53..278ec1a80 100644 --- a/packages/restapi/README.md +++ b/packages/restapi/README.md @@ -2073,6 +2073,49 @@ export interface IUser { Example response normal user: +**Version 1.2.x** + +```typescript +export interface IUser { + did: string; + wallets: string; + profilePicture: string | null; + publicKey: string; + encryptedPrivateKey: string; + encryptionType: string; + signature: string; + sigType: string; + about: string | null; + name: string | null; + encryptedPassword: string | null; + nftOwner: string | null; + numMsg: number; + allowedNumMsg: number; + linkedListHash?: string | null; + nfts?: [] | null; +} +``` + +| Parameter | Description | +| --- | --- | +| `did` | user decentralized identity | +| `wallets` | all wallets associated to the did | +| `profilePicture` | user chat profile picture. As of now i cannot be changed | +| `publicKey` | PGP public key | +| `encryptedPrivateKey` | encrypted private PGP key | +| `encryptionType` | encryption type used to encrypt the private key | +| `signature` | user payload signature used when creating a user | +| `sigType` | signature type used when creating a user | +| `about` | short user description | +| `name` | user name | +| `encryptedPassword` | encrypted password used to encrypt the private key for NFT chat | +| `nftOwner` | NFT owner address | +| `numMsg` | number of messages sent by the user | +| `allowedNumMsg` | number of messages allowed to be sent by the user | +| `linkedListHash` | cid from all messages this user has sent | +| `nfts` | array of NFTs owned by the user | + +Example response: ```typescript // PushAPI_user_get | Response - 200 OK { diff --git a/packages/restapi/yarn.lock b/packages/restapi/yarn.lock index 1a880b108..84c19b69e 100644 --- a/packages/restapi/yarn.lock +++ b/packages/restapi/yarn.lock @@ -44,6 +44,348 @@ "@ethereumjs/rlp" "^4.0.1" ethereum-cryptography "^1.1.2" +"@ethersproject/abi@^5.7.0", "@ethersproject/abi@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@^5.7.0", "@ethersproject/abstract-provider@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@^5.7.0", "@ethersproject/abstract-signer@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@^5.7.0", "@ethersproject/address@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@^5.7.0", "@ethersproject/base64@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@^5.7.0", "@ethersproject/basex@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@^5.7.0", "@ethersproject/bignumber@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@^5.7.0", "@ethersproject/bytes@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@^5.7.0", "@ethersproject/constants@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@^5.7.0", "@ethersproject/hash@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@^5.7.0", "@ethersproject/hdnode@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@^5.7.0", "@ethersproject/json-wallets@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@^5.7.0", "@ethersproject/keccak256@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@^5.7.0", "@ethersproject/logger@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@^5.7.0", "@ethersproject/networks@5.7.1": + version "5.7.1" + resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@^5.7.0", "@ethersproject/pbkdf2@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@^5.7.0", "@ethersproject/properties@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2": + version "5.7.2" + resolved "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@^5.7.0", "@ethersproject/random@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@^5.7.0", "@ethersproject/rlp@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@^5.7.0", "@ethersproject/sha2@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@^5.7.0", "@ethersproject/signing-key@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@^5.7.0", "@ethersproject/strings@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@^5.7.0", "@ethersproject/transactions@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@^5.7.0", "@ethersproject/web@5.7.1": + version "5.7.1" + resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@^5.7.0", "@ethersproject/wordlists@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" @@ -74,12 +416,12 @@ tweetnacl "^1.0.3" tweetnacl-util "^0.15.1" -"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": +"@noble/hashes@~1.2.0", "@noble/hashes@1.2.0": version "1.2.0" resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== -"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": +"@noble/secp256k1@~1.7.0", "@noble/secp256k1@1.7.1": version "1.7.1" resolved "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz" integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== @@ -153,6 +495,11 @@ resolved "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz" integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== +"@types/node@*": + version "20.2.4" + resolved "https://registry.npmjs.org/@types/node/-/node-20.2.4.tgz" + integrity sha512-ni5f8Xlf4PwnT/Z3f0HURc3ZSw8UyrqMqmM3L5ysa7VjHu8c3FOmIo1nKCcLrV/OAmtf3N4kFna/aJqxsfEtnA== + acorn-walk@^8.1.1: version "8.2.0" resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" @@ -163,6 +510,11 @@ acorn@^8.4.1: resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + ansi-colors@4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" @@ -217,7 +569,7 @@ argparse@^2.0.1: asn1.js@^5.0.0: version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz" integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== dependencies: bn.js "^4.0.0" @@ -240,16 +592,26 @@ base64-js@^1.3.1: resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + binary-extensions@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -bn.js@^4.0.0, bn.js@^4.11.8: +bn.js@^4.0.0, bn.js@^4.11.8, bn.js@^4.11.9: version "4.12.0" resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== +bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -272,6 +634,11 @@ braces@~3.0.2: dependencies: fill-range "^7.0.1" +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" @@ -302,12 +669,12 @@ case@^1.6.3: chai-as-promised@^7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" + resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz" integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== dependencies: check-error "^1.0.2" -chai@^4.3.7: +chai@^4.3.7, "chai@>= 2.1.2 < 5": version "4.3.7" resolved "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz" integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== @@ -394,16 +761,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" @@ -430,7 +797,7 @@ crypto-js@^4.1.1: resolved "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz" integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== -debug@4.3.4, debug@^4.3.2: +debug@^4.3.2, debug@4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -454,15 +821,28 @@ deep-eql@^4.1.2: dependencies: type-detect "^4.0.0" +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + diff@5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== +elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" emoji-regex@^8.0.0: version "8.0.0" @@ -478,7 +858,7 @@ end-of-stream@^1.1.0: err-code@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-3.0.1.tgz#a444c7b992705f2b120ee320b09972eef331c920" + resolved "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz" integrity sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA== escalade@^3.1.1: @@ -486,16 +866,16 @@ escalade@^3.1.1: resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-string-regexp@4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + ethereum-cryptography@^1.1.2: version "1.2.0" resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz" @@ -506,9 +886,45 @@ ethereum-cryptography@^1.1.2: "@scure/bip32" "1.1.5" "@scure/bip39" "1.1.1" +ethers@^5.6.8: + version "5.7.2" + resolved "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + ethjs-util@^0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" + resolved "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz" integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== dependencies: is-hex-prefixed "1.0.0" @@ -534,6 +950,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== + dependencies: + locate-path "^2.0.0" + find-up@5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" @@ -542,13 +965,6 @@ find-up@5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" - integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== - dependencies: - locate-path "^2.0.0" - flat@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" @@ -566,7 +982,7 @@ fsevents@~2.3.2: get-browser-rtc@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz#d1494e299b00f33fc8e9d6d3343ba4ba99711a2c" + resolved "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz" integrity sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ== get-caller-file@^1.0.1: @@ -620,11 +1036,28 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +hash.js@^1.0.0, hash.js@^1.0.3, hash.js@1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + he@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" @@ -632,7 +1065,7 @@ ieee754@^1.2.1: immer@^10.0.2: version "10.0.2" - resolved "https://registry.yarnpkg.com/immer/-/immer-10.0.2.tgz#11636c5b77acf529e059582d76faf338beb56141" + resolved "https://registry.npmjs.org/immer/-/immer-10.0.2.tgz" integrity sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA== inflight@^1.0.4: @@ -643,9 +1076,9 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3: +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@2: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== invert-kv@^2.0.0: @@ -719,6 +1152,11 @@ isexe@^2.0.0: resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + js-yaml@4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" @@ -789,17 +1227,15 @@ mimic-fn@^2.0.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimalistic-assert@^1.0.0: +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimatch@5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz" - integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== - dependencies: - brace-expansion "^2.0.1" +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== minimatch@^3.0.4: version "3.1.2" @@ -808,6 +1244,13 @@ minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + mocha-typescript@^1.1.17: version "1.1.17" resolved "https://registry.npmjs.org/mocha-typescript/-/mocha-typescript-1.1.17.tgz" @@ -993,7 +1436,7 @@ pump@^3.0.0: queue-microtask@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== randombytes@^2.1.0: @@ -1005,7 +1448,7 @@ randombytes@^2.1.0: readable-stream@^3.6.0: version "3.6.2" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== dependencies: inherits "^2.0.3" @@ -1036,9 +1479,14 @@ safe-buffer@^5.1.0, safe-buffer@~5.2.0: safer-buffer@^2.1.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + semver@^5.5.0: version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" @@ -1075,7 +1523,7 @@ signal-exit@^3.0.0: simple-peer@^9.11.1: version "9.11.1" - resolved "https://registry.yarnpkg.com/simple-peer/-/simple-peer-9.11.1.tgz#9814d5723f821b778b7fb011bdefcbd1e788e6cc" + resolved "https://registry.npmjs.org/simple-peer/-/simple-peer-9.11.1.tgz" integrity sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw== dependencies: buffer "^6.0.3" @@ -1086,6 +1534,13 @@ simple-peer@^9.11.1: randombytes "^2.1.0" readable-stream "^3.6.0" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" @@ -1112,13 +1567,6 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" @@ -1157,13 +1605,6 @@ strip-json-comments@3.1.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" @@ -1178,6 +1619,13 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" @@ -1219,14 +1667,14 @@ type-detect@^4.0.0, type-detect@^4.0.5: resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -typescript@^5.0.2: +typescript@^5.0.2, typescript@>=2.7: version "5.0.2" resolved "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz" integrity sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw== util-deprecate@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== v8-compile-cache-lib@^3.0.1: @@ -1273,6 +1721,11 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +ws@7.4.6: + version "7.4.6" + resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + y18n@^3.2.1: version "3.2.2" resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz" @@ -1283,7 +1736,7 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@20.2.4, yargs-parser@^20.2.2: +yargs-parser@^20.2.2, yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== @@ -1305,19 +1758,6 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0: - version "16.2.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yargs@^11.0.0: version "11.1.1" resolved "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz" @@ -1336,6 +1776,19 @@ yargs@^11.0.0: y18n "^3.2.1" yargs-parser "^9.0.2" +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + yn@3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" diff --git a/packages/uiweb/.eslintrc.json b/packages/uiweb/.eslintrc.json index 4308c24b9..55355314a 100644 --- a/packages/uiweb/.eslintrc.json +++ b/packages/uiweb/.eslintrc.json @@ -4,7 +4,9 @@ "overrides": [ { "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], - "rules": {} + "rules": { + "@typescript-eslint/consistent-type-imports": "error" + } }, { "files": ["*.ts", "*.tsx"], diff --git a/packages/uiweb/package.json b/packages/uiweb/package.json index b83e10a1e..091b6cec3 100644 --- a/packages/uiweb/package.json +++ b/packages/uiweb/package.json @@ -6,15 +6,17 @@ }, "dependencies": { "@pushprotocol/socket": "^0.5.0", + "@unstoppabledomains/resolution": "^8.5.0", "date-fns": "^2.28.0", - "emoji-picker-react": "^3.5.1", - "html-react-parser": "^1.4.13" + "emoji-picker-react": "^4.4.9", + "html-react-parser": "^1.4.13", + "gif-picker-react": "^1.1.0", + "font-awesome": "^4.7.0" }, "peerDependencies": { - "react": ">=16.8.0", - "styled-components": "^5.3.5", "@pushprotocol/restapi": "^1.2.15", - "@pushprotocol/socket": "^0.5.0" + "@pushprotocol/socket": "^0.5.0", + "react": ">=16.8.0", + "styled-components": "^5.3.5" } } - diff --git a/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotification.tsx b/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotification.tsx new file mode 100644 index 000000000..5e0d92db2 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotification.tsx @@ -0,0 +1,230 @@ +import React, { useEffect, useState, useContext } from 'react'; +import styled from 'styled-components'; + +import { MinimisedModalHeader } from './MinimisedModalHeader'; +import { Modal } from './modal'; +import type { ChatFeedsType} from '../../types'; +import { PUSH_TABS } from '../../types'; +import { CHAT_SOCKET_TYPE } from '../../types'; +import { + ChatMainStateContext, + ChatAndNotificationPropsContext, + NotificationMainStateContext, + ChatAndNotificationMainContext, +} from '../../context'; +import { Section } from '../reusables/sharedStyling'; +import useGetChatProfile from '../../hooks/chat/useGetChatProfile'; +import { chatLimit, device, requestLimit } from '../../config'; +import useFetchRequests from '../../hooks/chat/useFetchRequests'; +import useFetchChats from '../../hooks/chat/useFetchChats'; +import { + getAddress, + getDefaultFeedObject, + getNewChatUser, + walletToPCAIP10, +} from '../../helpers'; +import useFetchUserSubscriptions from '../../hooks/notifications/useFetchUserSubscriptions'; +import useChatNotificationSocket from '../../hooks/chatAndNotification/useChatNotificationSocket'; +import type { ChatMainStateContextType } from '../../context/chatAndNotification/chat/chatMainStateContext'; +import type { IFeeds } from '@pushprotocol/restapi'; +import useFetchChat from '../../hooks/chat/useFetchChat'; + +//make changes for users who dont have decryptedPgpPvtKey + +export const ChatAndNotification = () => { + const { setNewChat, setActiveTab, setActiveSubTab } = useContext( + ChatAndNotificationMainContext + ); + const { + setChatsFeed, + setRequestsFeed, + setSelectedChatId, + setSearchedChats, + chats, + setConnectedProfile, + requestsFeed, + chatsFeed, + selectedChatId, + setChats + } = useContext(ChatMainStateContext); + const { setInboxNotifsFeed, setSpamNotifsFeed } = useContext( + NotificationMainStateContext + ); + const { + decryptedPgpPvtKey, + account, + env, + activeChosenTab, + activeChat, + onClose, + } = useContext(ChatAndNotificationPropsContext); + const [modalOpen, setModalOpen] = useState(false); + const { fetchChatProfile } = useGetChatProfile(); + const { fetchRequests } = useFetchRequests(); + const { fetchChats } = useFetchChats(); + const { fetchChat } = useFetchChat(); + const { fetchUserSubscriptions } = useFetchUserSubscriptions(); + useChatNotificationSocket({}); + + useChatNotificationSocket({ socketType: CHAT_SOCKET_TYPE.CHAT }); + + useEffect(() => { + setChatsFeed({}); + setRequestsFeed({}); + setInboxNotifsFeed({}); + setSpamNotifsFeed({}); + // set active tab if present + if (activeChosenTab) { + setActiveTab(activeChosenTab); + setModalOpen(true); + } + else{ + setActiveTab(PUSH_TABS.CHATS); + } + setActiveSubTab(null); + setChats(new Map()); + setNewChat(false); + }, [account, env, activeChosenTab]); + + //make a helper for the function + const fetchRequestList = async () => { + const feeds = await fetchRequests({ page: 1, requestLimit }); + const firstFeeds: ChatFeedsType = { ...feeds }; + setRequestsFeed(firstFeeds); + }; + + useEffect(() => { + if (Object.keys(requestsFeed).length) { + return; + } + if (decryptedPgpPvtKey) { + fetchRequestList(); + } + }, [fetchRequests, decryptedPgpPvtKey, env]); + + const fetchChatList = async () => { + const feeds = await fetchChats({ page: 1, chatLimit }); + const firstFeeds: ChatFeedsType = { ...feeds }; + setChatsFeed(firstFeeds); + }; + + useEffect(() => { + if (Object.keys(chatsFeed).length) { + return; + } + if (decryptedPgpPvtKey) { + fetchChatList(); + } + }, [fetchChats, env, account]); + + useEffect(() => { + (async () => { + let user; + if (account) { + user = await fetchChatProfile({ profileId: account }); + + if (user) setConnectedProfile(user); + } + })(); + }, [account]); + + useEffect(() => { + (async () => { + fetchUserSubscriptions(); + })(); + }, [env, account]); + + useEffect(() => { + (async () => { + if (activeChat) { + const address = await getAddress(activeChat, env); + if (address) { + setModalOpen(true); + setSelectedChatId(walletToPCAIP10(address).toLowerCase()); + let selectedChat = chatsFeed[walletToPCAIP10(address).toLowerCase()] || requestsFeed[walletToPCAIP10(address).toLowerCase()]; + if (!selectedChat) { + selectedChat = (await fetchChat({ + recipientAddress: walletToPCAIP10(address), + })) as IFeeds; + if (!Object.keys(selectedChat|| {}).length) { + const result = await getNewChatUser({ + searchText: address, + fetchChatProfile, + env, + }); + + if (result) { + selectedChat = getDefaultFeedObject({ user: result }); + } + } + + } + setSearchedChats({ + [selectedChat.did.toLowerCase() ?? selectedChat.chatId]: selectedChat, + }); + + } + else{ + setSearchedChats(null); + setSelectedChatId(null); + } + } else { + + setSelectedChatId(null); + setSearchedChats(null); + } + // setChats(new Map()) + })(); + }, [activeChat,env,account]); + + const onMaximizeMinimizeToggle = () => { + setModalOpen(!modalOpen); + }; + + const toggleOverflow = (val: string) => { + if (typeof window != 'undefined' && window.document) { + document.body.style.overflowY = val; + } + }; + + + return ( + toggleOverflow('hidden')} + onMouseLeave={() => toggleOverflow('unset')} + > + + {modalOpen && } + + ); +}; + +//styles + +const Container = styled(Section)` + border: 1px solid #dddddf; + padding:0 20px 0 21px; + box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.08), 0px 0px 96px rgba(0, 0, 0, 0.12); + backdrop-filter: blur(5px); + /* Note: backdrop-filter has minimal browser support */ + border-radius: 8px; + // @media ${device.mobileL} { + // width: 350px; + // } + @media ${device.mobileL} { + width: 330px; + padding: 0px 12px 0 12px; + } +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotificationWidget.tsx b/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotificationWidget.tsx new file mode 100644 index 000000000..37e3dc39d --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotificationWidget.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { ChatAndNotificationMainContextProvider, ChatAndNotificationPropsContext, NotificationMainStateContextProvider } from '../../context'; +import 'font-awesome/css/font-awesome.min.css'; +import { Constants } from '../../config'; +import { ChatMainStateContextProvider } from '../../context'; + +import { ChatAndNotification } from './ChatAndNotification'; +import type { Env, SignerType } from '@pushprotocol/restapi'; +import { pCAIP10ToWallet, } from '../../helpers'; +import type { PushTabs } from '../../types'; +import { PUSH_TABS } from '../../types'; +import type { WithRequiredProperty } from '../../utilities'; + +export type ChatAndNotificationProps = { + account: string; + decryptedPgpPvtKey: string; //have to make it optional for new users + activeTab?: PushTabs, + activeChat?: string, + onClose?: () => void, + signer?: WithRequiredProperty + env?: Env; +}; + +//make changes for users who dont have decryptedPgpPvtKey +export const ChatAndNotificationWidget: React.FC = ({ + account, + decryptedPgpPvtKey = null, + activeTab = null, + activeChat = null, + onClose = null, + signer = null, + env = Constants.ENV.PROD, +}) => { + + const chatAndNotificationPropsData = { + account: pCAIP10ToWallet(account), + decryptedPgpPvtKey, + activeChosenTab: activeTab, + activeChat: activeChat, + onClose, + signer, + env, + }; + + return ( + + + + + + + + + + + ); +}; + +//styles + + + diff --git a/packages/uiweb/src/lib/components/chatAndNotification/MinimisedModalHeader.tsx b/packages/uiweb/src/lib/components/chatAndNotification/MinimisedModalHeader.tsx new file mode 100644 index 000000000..abb71f61c --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/MinimisedModalHeader.tsx @@ -0,0 +1,290 @@ +import React, { useContext } from 'react'; +import styled from 'styled-components'; +import { MaximizeIcon } from '../../icons/Maximize'; +import { NewChatIcon } from '../../icons/NewChat'; +import { BackIcon } from '../../icons/Back'; +import { MinimizeIcon } from '../../icons/Minimize'; +import { Section, Span, Image, Div } from '../reusables/sharedStyling'; +import { + ChatMainStateContext, + ChatAndNotificationPropsContext, + NotificationMainStateContext, + ChatAndNotificationMainContext, +} from '../../context'; +import type { PushSubTabs, PushTabs } from '../../types'; +import { PUSH_SUB_TABS, PUSH_TABS } from '../../types'; +import { useResolveWeb3Name } from '../../hooks'; +import { pCAIP10ToWallet, shortenText } from '../../helpers'; +import { ethers } from 'ethers'; +import { PushSubTabTitle } from '../../config'; +import { Tooltip } from '../reusables'; +import type { ChatAndNotificationMainContextType } from '../../context/chatAndNotification/chatAndNotificationMainContext'; +import type { ChatMainStateContextType } from '../../context/chatAndNotification/chat/chatMainStateContext'; +import { ChatSnap } from './modal/sidebar/chatSidebar/ChatSnap'; + +type MinimisedModalHeaderPropType = { + onMaximizeMinimizeToggle: () => void; + modalOpen: boolean; +}; + +export const UnreadChats = ({ + // numberOfUnreadMessages, + background, + color, +}: { + // numberOfUnreadMessages: string; + background?: string; + color?: string; +}) => { + return ( + + {/* {numberOfUnreadMessages} */} + + ); +}; + +export const MessageBoxHeader = () => { + const { activeTab, setActiveTab, setActiveSubTab, activeSubTab } = + useContext( + ChatAndNotificationMainContext + ); + const { + selectedChatId, + chatsFeed, + requestsFeed, + web3NameList, + searchedChats, + setSearchedChats, + setSelectedChatId, + } = useContext(ChatMainStateContext); + const { env } = useContext(ChatAndNotificationPropsContext); + const { spamNotifsFeed } = useContext(NotificationMainStateContext); + const selectedChat = + chatsFeed[selectedChatId as string] || + requestsFeed[selectedChatId as string] || + (Object.keys(searchedChats || {}).length + ? searchedChats![selectedChatId as string] + : null); + useResolveWeb3Name(selectedChat?.did, env); + const walletLowercase = pCAIP10ToWallet(selectedChat?.did)?.toLowerCase(); + const checksumWallet = walletLowercase + ? ethers.utils.getAddress(walletLowercase) + : null; + const web3Name = checksumWallet ? web3NameList[checksumWallet.toLowerCase()] : null; + const handleBack = () => { + if ( + activeSubTab && + ((activeSubTab === PUSH_SUB_TABS.REQUESTS && + Object.keys(requestsFeed || {}).length) || + (activeSubTab === PUSH_SUB_TABS.SPAM && + Object.keys(spamNotifsFeed || {}).length)) + ) { + setActiveSubTab(PUSH_SUB_TABS[activeSubTab as PushSubTabs]); + } else { + setActiveTab(PUSH_TABS[activeTab as PushTabs]); + } + if (activeSubTab === PUSH_SUB_TABS.REQUESTS || !activeSubTab) { + setSelectedChatId(null); + + setSearchedChats(null); + } + }; + return selectedChat ? ( +
+
handleBack()} + > + +
+ +
+ profile picture + + + {' '} + {selectedChat?.name + ? shortenText(selectedChat?.name, 30) + : web3Name ?? shortenText(selectedChat?.did?.split(':')[1], 20)} + + +
+
+ ) : null; +}; + +export const SubTabHeader = () => { + const { activeTab, setActiveTab, activeSubTab } = + useContext( + ChatAndNotificationMainContext + ); + const { setSearchedChats, setSelectedChatId } = + useContext(ChatMainStateContext); + const { setSearchedNotifications } = useContext( + NotificationMainStateContext + ); + return ( +
+
{ + setActiveTab(activeTab); + if (activeSubTab === PUSH_SUB_TABS.REQUESTS) { + setSearchedChats(null); + setSelectedChatId(null); + } + if (activeSubTab === PUSH_SUB_TABS.SPAM) { + setSearchedNotifications(null); + } + }} + > + +
+ + + {PushSubTabTitle[activeSubTab as PushSubTabs].title} + +
+ ); +}; + +export const MinimisedModalHeader: React.FC = ({ + onMaximizeMinimizeToggle, + modalOpen, +}) => { + const { newChat, setNewChat, setActiveTab, activeSubTab } = + useContext( + ChatAndNotificationMainContext + ); + + const { + selectedChatId, + chatsFeed, + requestsFeed, + setSearchedChats, + setSelectedChatId, + searchedChats, + } = useContext(ChatMainStateContext); + + const SnapMessageHeader = () => { + const selectedChat = + chatsFeed[selectedChatId as string] || + requestsFeed[selectedChatId as string] || + (Object.keys(searchedChats || {}).length + ? searchedChats![selectedChatId as string] + : null); + return ( + + ); + }; + + const condition = + (selectedChatId && modalOpen) || + (!selectedChatId && modalOpen && activeSubTab); + const snapCondition = + (selectedChatId && !modalOpen); + return ( + + {selectedChatId && + !!( + Object.keys(chatsFeed || {}).length || + Object.keys(requestsFeed || {}).length || + Object.keys(searchedChats || {}).length + ) && + modalOpen && } + + {selectedChatId && !modalOpen && } + + {!selectedChatId && modalOpen && activeSubTab && } + {((!selectedChatId && modalOpen && !activeSubTab) || + (!modalOpen && !selectedChatId)) && ( +
+ { + setActiveTab(PUSH_TABS.CHATS); + setSearchedChats(null); + setSelectedChatId(null); + }} + > + {newChat ? 'New Message' : 'Messages'} + + {/* */} +
+ )} +
+ {((!selectedChatId && modalOpen && !activeSubTab && !newChat) || + (!modalOpen && !selectedChatId)) && ( +
{ + if (modalOpen) { + setNewChat(true); + } + }} + > + +
+ )} +
+ {modalOpen ? : } +
+
+
+ ); +}; + +//styles +const Container = styled(Section)` + box-sizing: border-box; +`; + + diff --git a/packages/uiweb/src/lib/components/chatAndNotification/index.ts b/packages/uiweb/src/lib/components/chatAndNotification/index.ts new file mode 100644 index 000000000..cba28dac9 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/index.ts @@ -0,0 +1,2 @@ +export { ChatAndNotificationWidget } from "./ChatAndNotificationWidget"; + diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/Modal.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/Modal.tsx new file mode 100644 index 000000000..73fc93ac7 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/Modal.tsx @@ -0,0 +1,40 @@ +import React, { useContext } from 'react'; +import { ChatAndNotificationMainContext, ChatMainStateContext } from '../../../context'; +import type { ChatMainStateContextType } from '../../../context/chatAndNotification/chat/chatMainStateContext'; +import type { ChatAndNotificationMainContextType } from '../../../context/chatAndNotification/chatAndNotificationMainContext'; +import { PUSH_SUB_TABS } from '../../../types'; +import { Section } from '../../reusables/sharedStyling'; +import { Spinner } from '../../reusables/Spinner'; +import { MessageBox } from './messageBox/MessageBox'; +import { RequestsFeedList } from './sidebar/chatSidebar/RequestsFeedList'; +import { SpamNotificationFeedList } from './sidebar/notificationSidebar/SpamNotificationFeedList'; +import { Sidebar } from './sidebar/Sidebar'; + +export const Modal = () => { + + const { activeSubTab } = useContext(ChatAndNotificationMainContext) + const { selectedChatId, chatsFeed, requestsFeed, searchedChats } = useContext(ChatMainStateContext); + + + return ( +
+ {!selectedChatId && !activeSubTab && } + {!selectedChatId && activeSubTab === PUSH_SUB_TABS.REQUESTS && ( + + )} + {activeSubTab === PUSH_SUB_TABS.SPAM && ( + + )} + + {selectedChatId && + ((Object.keys(chatsFeed || {}).length || + Object.keys(requestsFeed || {}).length || Object.keys(searchedChats || {}).length) ? ( + + ) : ( + + ))} +
+ ); +}; + +//styles diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/index.ts b/packages/uiweb/src/lib/components/chatAndNotification/modal/index.ts new file mode 100644 index 000000000..c5d9da616 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/index.ts @@ -0,0 +1 @@ +export * from './Modal' \ No newline at end of file diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/messageBox/MessageBox.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/messageBox/MessageBox.tsx new file mode 100644 index 000000000..409fba9b3 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/messageBox/MessageBox.tsx @@ -0,0 +1,516 @@ +import { + ChatMainStateContext, + ChatAndNotificationPropsContext, + ChatAndNotificationMainContext, +} from '../../../../context'; +import React, { useEffect, useRef, useContext } from 'react'; +import { Image, Section, Span } from '../../../reusables/sharedStyling'; +import styled from 'styled-components'; +import useFetchHistoryMessages from '../../../../hooks/chat/useFetchHistoryMessages'; +import type { IMessageIPFS } from '@pushprotocol/restapi'; +import { Spinner } from '../../../reusables/Spinner'; +import moment from 'moment'; +import { + dateToFromNowDaily, + formatFileSize, + shortenText, +} from '../../../../helpers'; +import { pCAIP10ToWallet } from '../../../../helpers'; +import useApproveChatRequest from '../../../../hooks/chat/useApproveChatRequest'; +import type { FileMessageContent } from '../../../../types'; + +import { Typebar } from './typebar/Typebar'; +import { FILE_ICON } from '../../../../config'; +import { EncryptionIcon } from '../../../../icons/Encryption'; +import { NoEncryptionIcon } from '../../../../icons/NoEncryption'; +import type { ChatMainStateContextType } from '../../../../context/chatAndNotification/chat/chatMainStateContext'; + +const CHATS_FETCH_LIMIT = 15; + +const EncryptionMessageContent = { + ENCRYPTED: { + IconComponent: , + text: 'Messages are end-to-end encrypted. Only users in this chat can view or listen to them.', + }, + NO_ENCRYPTED: { + IconComponent: , + text: 'Messages are not encrypted until chat request is accepted.', + }, +}; +const EncryptionMessage = ({ id }: { id: 'ENCRYPTED' | 'NO_ENCRYPTED' }) => { + return ( +
+ {EncryptionMessageContent[id].IconComponent} + + + {EncryptionMessageContent[id].text} + +
+ ); +}; + +const FileCard = ({ + chat, + position, +}: { + chat: IMessageIPFS; + position: number; +}) => { + const fileContent: FileMessageContent = JSON.parse(chat.messageContent); + const name = fileContent.name; + + const content = fileContent.content as string; + const size = fileContent.size; + + return ( +
+ extension icon +
+ + {shortenText(name, 11)} + + + {formatFileSize(size)} + +
+ + +
+ ); +}; + +const ImageCard = ({ + chat, + position, +}: { + chat: IMessageIPFS; + position: number; +}) => { + return ( +
+ +
+ ); +}; + +const GIFCard = ({ + chat, + position, +}: { + chat: IMessageIPFS; + position: number; +}) => { + return ( +
+ +
+ ); +}; +const MessageCard = ({ + chat, + position, +}: { + chat: IMessageIPFS; + position: number; +}) => { + const time = moment(chat.timestamp).format('hh:mm a'); + return ( +
+ {' '} +
+ {chat.messageContent.split('\n').map((str) => ( + + {str} + + ))} +
+ + {time} + +
+ ); +}; + +const Messages = ({ chat }: { chat: IMessageIPFS }) => { + const { account } = useContext(ChatAndNotificationPropsContext); + const position = + pCAIP10ToWallet(chat.fromDID).toLowerCase() !== account.toLowerCase() + ? 0 + : 1; + if (chat.messageType === 'GIF') { + return ; + } + if (chat.messageType === 'Image') { + return ; + } + if (chat.messageType === 'File') { + return ; + } + return ; +}; + +export const MessageBox = () => { + const { activeTab, setActiveTab } = useContext( + ChatAndNotificationMainContext + ); + const { + selectedChatId, + chatsFeed, + requestsFeed, + chats, + setRequestsFeed, + setChatFeed, + setSearchedChats, + searchedChats, + setSelectedChatId, + } = useContext(ChatMainStateContext); + const { account, env, decryptedPgpPvtKey } = useContext( + ChatAndNotificationPropsContext + ); + + const selectedChat = + chatsFeed[selectedChatId as string] || + requestsFeed[selectedChatId as string] || + (searchedChats ? searchedChats[selectedChatId as string] : null); + + const requestFeedids = Object.keys(requestsFeed); + const selectedMessages = chats.get(selectedChatId as string); + + const dates = new Set(); + const listInnerRef = useRef(null); + const bottomRef = useRef(null); + + const { historyMessages, loading } = useFetchHistoryMessages(); + const { approveChatRequest, loading: approveLoading } = useApproveChatRequest(); + + type RenderDataType = { + chat: IMessageIPFS; + dateNum: string; + }; + + const renderDate = ({ chat, dateNum }: RenderDataType) => { + const timestampDate = dateToFromNowDaily(chat.timestamp as number); + dates.add(dateNum); + return ( + + {timestampDate} + + ); + }; + + const scrollToBottom = (behavior?: string | null) => { + bottomRef?.current?.scrollIntoView( + !behavior ? true : { behavior: 'smooth' } + ); + }; + + const onScroll = async () => { + if (listInnerRef.current) { + const { scrollTop } = listInnerRef.current; + if (scrollTop === 0) { + const content = listInnerRef.current; + const curScrollPos = content.scrollTop; + const oldScroll = content.scrollHeight - content.clientHeight; + + await getChatCall(); + + const newScroll = content.scrollHeight - content.clientHeight; + content.scrollTop = curScrollPos + (newScroll - oldScroll); + } + } + }; + useEffect(() => { + scrollToBottom(); + }, [selectedChatId]); + + useEffect(() => { + if ( + selectedChatId && + selectedMessages && + selectedMessages?.messages.length + // selectedMessages?.messages.length <= CHATS_FETCH_LIMIT + ) { + scrollToBottom(null); + } + }, [chats.get(selectedChatId as string)]); + + //optimise it + const getChatCall = async () => { + let threadHash = null; + + if (!selectedMessages && selectedChat?.threadhash) { + threadHash = selectedChat?.threadhash; + } else if (chats.size && selectedMessages?.lastThreadHash) { + threadHash = selectedMessages?.lastThreadHash; + } + if (threadHash) { + await historyMessages({ + limit: CHATS_FETCH_LIMIT, + threadHash, + }); + } + }; + + useEffect(() => { + // // only for user who has requests but hasn't created user in push chat yet + // if (selectedMessages?.messages.length) { + // return; + // } + + (async function () { + + await getChatCall(); + })(); + }, [selectedChatId]); + + const handleApproveChatRequest = async () => { + if (selectedChatId) { + try { + if (!decryptedPgpPvtKey) { + return; + } + const response = await approveChatRequest({ + senderAddress: selectedChatId, + }); + if (response) { + const updatedRequestsfeed = { ...requestsFeed }; + const selectedRequest = updatedRequestsfeed[selectedChatId]; + delete updatedRequestsfeed[selectedChatId]; + setChatFeed(selectedChatId, selectedRequest); + setSearchedChats(null); + setRequestsFeed(updatedRequestsfeed); + } + } catch (error_: Error | any) { + console.log(error_.message); + } + } else { + return; + } + }; + + return ( +
+ + <> + {selectedChat && !selectedChat.publicKey ? ( + + ) : ( + + )} + {loading ? : ''} + + {selectedMessages ? ( + + {selectedMessages?.messages.map( + (chat: IMessageIPFS, index: number) => { + const dateNum = moment(chat.timestamp).format('L'); + return ( + <> + {dates.has(dateNum) + ? null + : renderDate({ chat, dateNum })} + + + ); + } + )} + {requestFeedids.includes(selectedChatId as string) && ( +
+ + Please accept the Push Chat request to continue the + conversation + + +
+ )} +
+ + ) : null} + + + + {!requestFeedids.includes(selectedChatId as string) && ( + + )} +
+ ); +}; + +//styles + +const MessageListCard = styled(Section)` + +`; + +const Container = styled(Section)` +&::-webkit-scrollbar-thumb { + background: rgb(181 181 186); + border-radius: 10px; +} + +&::-webkit-scrollbar { + width: 5px; +} +`; +const FileDownloadIcon = styled.i` + color: #575757; +`; + +const FileDownloadIconAnchor = styled.a` + font-size: 20px; +`; + +const Button = styled.button` + border: none; + cursor: pointer; + border-radius: 8px; + margin:15px 0px 8px 0px; + background: #0D67FE; + color: white; + width: 100%; + font-size: 16px; + font-weight: 600; + line-height: 24px; + max-height: 48px; + min-height: 48px; + padding: 0px 24px; + display: flex; + justify-content: center; + align-items: center; +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/messageBox/typebar/Typebar.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/messageBox/typebar/Typebar.tsx new file mode 100644 index 000000000..d5b4e0af6 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/messageBox/typebar/Typebar.tsx @@ -0,0 +1,340 @@ +import type { ChangeEvent } from 'react'; +import React, { useState, useContext, useRef, useEffect } from 'react'; +import styled from 'styled-components'; +import { Div, Section } from '../../../../reusables/sharedStyling'; +import { EmojiIcon } from '../../../../../icons/Emoji'; +import { SendIcon } from '../../../../../icons/Send'; +import { GifIcon } from '../../../../../icons/Gif'; +import { AttachmentIcon } from '../../../../../icons/Attachment'; +import usePushSendMessage from '../../../../../hooks/chat/usePushSendMessage'; +import { + ChatAndNotificationMainContext, + ChatMainStateContext, +} from '../../../../../context'; +import useFetchRequests from '../../../../../hooks/chat/useFetchRequests'; +import { Spinner } from '../../../../reusables/Spinner'; +import type { EmojiClickData } from 'emoji-picker-react'; +import EmojiPicker from 'emoji-picker-react'; +import { device, PUBLIC_GOOGLE_TOKEN } from '../../../../../config'; +import GifPicker from 'gif-picker-react'; +import { useClickAway, useDeviceWidthCheck } from '../../../../../hooks'; +import type { FileMessageContent } from '../../../../../types'; +import type { ChatMainStateContextType } from '../../../../../context/chatAndNotification/chat/chatMainStateContext'; +import type { ChatAndNotificationMainContextType } from '../../../../../context/chatAndNotification/chatAndNotificationMainContext'; + +type GIFType = { + url: string; + height: number; + width: number; +}; + +type TypebarPropType = { + scrollToBottom: () => void; +}; +const requestLimit = 30; +const page = 1; +export const Typebar: React.FC = ({ scrollToBottom }) => { + const [typedMessage, setTypedMessage] = useState(''); + const [showEmojis, setShowEmojis] = useState(false); + const [gifOpen, setGifOpen] = useState(false); + const modalRef = useRef(null); + const fileUploadInputRef = React.useRef(null); + const { selectedChatId, chatsFeed, setSearchedChats, requestsFeed } = + useContext(ChatMainStateContext); + const { newChat, setNewChat } = + useContext( + ChatAndNotificationMainContext + ); + const { sendMessage, loading } = usePushSendMessage(); + const [filesUploading, setFileUploading] = useState(false); + const { fetchRequests } = useFetchRequests(); + const onChangeTypedMessage = (val: string) => { + if (val.trim() !== '') setTypedMessage(val); + }; + const isMobile = useDeviceWidthCheck(425); + + useClickAway(modalRef, () => { + setGifOpen(false); + setShowEmojis(false); + }); + const sendPushMessage = async (content: string, type: string) => { + try { + await sendMessage({ + message: content, + receiver: selectedChatId as string, + messageType: type as any, + }); + scrollToBottom(); + + if ( + chatsFeed[selectedChatId as string] || + requestsFeed[selectedChatId as string] + ) + setSearchedChats(null); + if (newChat) setNewChat(false); + if (!chatsFeed[selectedChatId as string]) + fetchRequests({ page, requestLimit }); + } catch (error) { + console.log(error); + //handle error + } + }; + + const sendGIF = async (emojiObject: GIFType) => { + sendPushMessage(emojiObject.url as string, 'GIF'); + setGifOpen(false); + }; + + const sendTextMsg = async () => { + if (typedMessage.trim() !== '') { + await sendPushMessage(typedMessage as string, 'Text'); + setTypedMessage(''); + } + }; + const addEmoji = (emojiData: EmojiClickData, event: MouseEvent): void => { + setTypedMessage(typedMessage + emojiData.emoji); + setShowEmojis(false); + }; + + const handleUploadFile = () => { + if (fileUploadInputRef.current) { + fileUploadInputRef.current.click(); + } + }; + + const uploadFile = async ( + e: ChangeEvent + ): Promise => { + if (!(e.target instanceof HTMLInputElement)) { + return; + } + if (!e.target.files) { + return; + } + if ( + e.target && + (e.target as HTMLInputElement).files && + ((e.target as HTMLInputElement).files as FileList).length + ) { + const file: File = e.target.files[0]; + if (file) { + try { + const TWO_MB = 1024 * 1024 * 2; + if (file.size > TWO_MB) { + console.log('Files larger than 2mb is now allowed'); + throw new Error('Files larger than 2mb is now allowed'); + } + setFileUploading(true); + const messageType = file.type.startsWith('image') ? 'Image' : 'File'; + const reader = new FileReader(); + let fileMessageContent: FileMessageContent; + reader.readAsDataURL(file); + reader.onloadend = async (e): Promise => { + fileMessageContent = { + content: e.target!.result as string, + name: file.name, + type: file.type, + size: file.size, + }; + + sendPushMessage(JSON.stringify(fileMessageContent), messageType); + }; + } catch (err) { + console.log(err); + } finally { + setFileUploading(false); + } + } + } + }; + + //for fixing the typebar height + const textAreaRef = useRef(null); + useEffect(() => { + if (textAreaRef?.current?.style) { + textAreaRef.current.style.height = 25 + 'px'; + const scrollHeight = textAreaRef.current?.scrollHeight; + textAreaRef.current.style.height = scrollHeight + 'px'; + } + }, [textAreaRef, typedMessage]); + + return ( + + +
+
setShowEmojis(!showEmojis)} + > + +
+ + {showEmojis && ( +
+ +
+ )} + { + if (event.key === 'Enter' && !event.shiftKey) { + event.preventDefault(); + sendTextMsg(); + } + }} + placeholder="Type your message..." + onChange={(e) => onChangeTypedMessage(e.target.value)} + value={typedMessage} + ref={textAreaRef} + rows={1} + /> +
+ +
setGifOpen(!gifOpen)} + > + +
+ + {gifOpen && ( +
+ +
+ )} +
+ {!filesUploading && ( + <> +
setNewChat(true)} + > + +
+ + uploadFile(e)} + /> + + )} +
+ {!(loading || filesUploading) && ( +
sendTextMsg()} + > + +
+ )} + + {(loading || filesUploading) && ( +
+ +
+ )} +
+
+
+ ); +}; + +//styles +const Container = styled.div` + width: 100%; + border-top: 1px solid #dddddf; + overflow: hidden; + padding: 15px 0px; +`; +const TypebarSection = styled(Section)` + gap: 10px; + @media ${device.mobileL} { + gap: 0px; + } +`; +const SendSection = styled(Section)` + gap: 11.5px; + @media ${device.mobileL} { + gap: 7.5px; + } +`; +const MultiLineInput = styled.textarea` + font-family: inherit; + font-weight: 400; + transform: translateY(3px); + font-size: 16px; + outline: none; + overflow-y: auto; + box-sizing: border-box; + border: none; + color: #000; + resize: none; + flex: 1; + padding-right: 5px; + align-self: end; + @media ${device.mobileL} { + font-size: 14px; + } + &&::-webkit-scrollbar { + width: 4px; + padding-right: 0px; + } + ::-webkit-scrollbar-thumb { + background: rgb(181 181 186); + border-radius: 10px; + height: 50px; + } + ::placeholder { + color: #000; + transform: translateY(1px); + @media ${device.mobileL} { + font-size: 14px; + } + } + + min-height: 25px; + max-height: 80px; + word-break: break-word; +`; +const FileInput = styled.input` + display: none; +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/Search.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/Search.tsx new file mode 100644 index 000000000..0d1c3a6a5 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/Search.tsx @@ -0,0 +1,180 @@ +import { + PUSH_TABS, + type ChatFeedsType, + type NotificationFeedsType, +} from '../../../../types'; +import React, { useContext, useState } from 'react'; +import styled from 'styled-components'; +import { SearchIcon } from '../../../../icons/Search'; +import { CloseIcon } from '../../../../icons/Close'; +import { Spinner } from '../../../reusables/Spinner'; +import { Div, Section, Span } from '../../../reusables/sharedStyling'; +import type { + ChatMainStateContextType} from '../../../../context/chatAndNotification/chat/chatMainStateContext'; +import { + ChatMainStateContext +} from '../../../../context/chatAndNotification/chat/chatMainStateContext'; +import { BackIcon } from '../../../../icons/Back'; +import { ChatAndNotificationMainContext } from '../../../../context'; +import type { ChatAndNotificationMainContextType } from '../../../../context/chatAndNotification/chatAndNotificationMainContext'; + +type SearchPropType = { + feed: ChatFeedsType | NotificationFeedsType; + handleSearch: any; + onSearchReset: () => void; + placeholder: string; +}; + +export const Search: React.FC = ({ + feed, + handleSearch, + onSearchReset, + placeholder, +}) => { + const [searchedText, setSearchedText] = useState(''); + const [loading, setLoading] = useState(false); + const onChangeSearchText = (val: string) => { + setSearchedText(val); + }; + + const { setSearchedChats } = + useContext(ChatMainStateContext); + + const { + newChat, + setActiveTab + } = useContext(ChatAndNotificationMainContext) + React.useEffect(() => { + setLoading(true); + const getData = setTimeout(() => { + onSearch(); + setLoading(false); + }, 2000); + return () => clearTimeout(getData); + }, [searchedText]); + + + const onSearch = () =>{ + if (searchedText.trim() !== '') { + handleSearch({ searchedText, feed }); + } else { + onSearchReset(); + } + } + + return ( + + {newChat &&
{ + setSearchedChats(null); + setActiveTab(PUSH_TABS.CHATS); + }} + > + +
} +
+ onChangeSearchText(e.target.value)} + placeholder={placeholder} + onKeyDown={(event) => { + if (event.key === 'Enter') { + onSearch() + } + }} + /> + + {!loading && !searchedText && ( +
onSearch()} + > + +
+ )} + {!loading && searchedText && ( +
{ + setSearchedText(''); + onSearchReset(); + }} + width="17.49px" + height="17.49px" + > + +
+ )} + {loading && } +
+
+
+ ); +}; + +//styles +const Container = styled(Section)` + border-radius: 4px; +`; + +// background: #ededee; +// border: none; +// width: 90%; +// &:focus { +// outline: none; +// background-origin: border; +// background-clip: padding-box, border-box; +// } +// &::placeholder { +// color: #7a7a85; +// } +// `; + +// const Image = styled.img` +// vertical-align: middle; +// cursor: pointer; +// `; + +// const SubSection = styled(Section)` +// background: #ffffff; +// border: 1px solid #c8c8cb; +// border-radius: 8px; +// flex: 1; +// padding: 10px 10px 10px 15px; +// margin-left: 18px; +// `; + +const Input = styled.input` + border: none; + background: #ededee; + width: 100%; + flex: 1; + margin-left: 10px; + font-style: normal; + font-weight: 400; + font-size: 16px; + line-height: 24px; + &:focus { + outline: none; + background-origin: border; + background-clip: padding-box, border-box; + } + &::placeholder { + color: #62626a; + } +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/Sidebar.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/Sidebar.tsx new file mode 100644 index 000000000..4e090d9fb --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/Sidebar.tsx @@ -0,0 +1,460 @@ +import React, { useContext } from 'react'; +import styled from 'styled-components'; +import { ChatList } from './chatSidebar/ChatList'; +import { Search } from './Search'; +import type { + ChatFeedsType, + NotificationFeedsType, + PushSubTabs, + PushTabs, +} from '../../../../types'; +import { SIDEBAR_PLACEHOLDER_KEYS } from '../../../../types'; +import { PUSH_SUB_TABS, PUSH_TABS } from '../../../../types'; +import { + ChatMainStateContext, + ChatAndNotificationPropsContext, + NotificationMainStateContext, + ChatAndNotificationMainContext, +} from '../../../../context'; +import useFetchChats from '../../../../hooks/chat/useFetchChats'; +import { Section, Span, Div } from '../../../reusables/sharedStyling'; +import { ChatsFeedList } from './chatSidebar/ChatsFeedList'; +import type { ChatMainStateContextType } from '../../../../context/chatAndNotification/chat/chatMainStateContext'; +import { AngleArrowIcon } from '../../../../icons/AngleArrow'; +import { device, PushSubTabTitle } from '../../../../config'; +import { + getAddress, + getDefaultFeedObject, + getNewChatUser, + getObjectsWithMatchingKeys, + getSearchedNotificationsList, + shortenNumber, + walletToPCAIP10, +} from '../../../../helpers'; +import { SpamIconSvg } from '../../../../icons/Spam'; +import { InboxNotificationFeedList } from './notificationSidebar/InboxNotificationFeedList'; +import useGetChatProfile from '../../../../hooks/chat/useGetChatProfile'; +import { NotificationFeedList } from './notificationSidebar/NotificationFeedList'; +import { SidebarPlaceholder } from './SidebarPlaceholder'; +import type { ChatAndNotificationMainContextType } from '../../../../context/chatAndNotification/chatAndNotificationMainContext'; +import useFetchChat from '../../../../hooks/chat/useFetchChat'; +import type { IFeeds } from '@pushprotocol/restapi'; + +export type TabPropType = { + tabName: string; + tabValue: PushTabs; +}; + +type SidebarSubTabsPropType = { + subTab: { + title: string; + subTitle: string; + icon: any; + }; + tabValue: PushSubTabs; + isClickable?: boolean; +}; + +const Tab: React.FC = ({ tabName, tabValue }) => { + const { activeTab, setActiveTab } = + useContext( + ChatAndNotificationMainContext + ); + const { setSearchedChats, setSelectedChatId } = + useContext(ChatMainStateContext); + const { setSearchedNotifications } = useContext( + NotificationMainStateContext + ); + + // const UnreadChats = () => { + // return ( + //
+ // + // 2 + // + //
+ // ) + //} + return ( +
{ + setActiveTab(tabValue); + if (activeTab === PUSH_TABS.CHATS) { + setSearchedChats(null); + setSelectedChatId(null); + } else if (activeTab === PUSH_TABS.APP_NOTIFICATIONS) { + setSearchedNotifications(null); + } + }} + borderColor={activeTab === tabValue ? '#0D67FE' : '#C8C8CB'} + borderStyle={ + activeTab === tabValue + ? ' solid ' + : tabValue === PUSH_TABS.CHATS + ? 'solid none solid solid' + : 'solid solid solid none' + } + borderWidth="2px" + borderRadius={ + activeTab === tabValue + ? '8px' + : tabValue === PUSH_TABS.CHATS + ? '8px 0px 0px 8px' + : '0px 8px 8px 0px' + } + position="relative" + background={activeTab === tabValue ? '#F0F5FF;' : '#FFF'} + left={tabValue === PUSH_TABS.APP_NOTIFICATIONS ? '-2.2px' : 'auto'} + right={tabValue === PUSH_TABS.CHATS ? '-2.6px' : 'auto'} + padding="8px 0" + zIndex={activeTab === tabValue ? '10' : '0'} + > + + {tabName} + + {/* */} +
+ ); +}; + +const SidebarTabs = () => { + return ( +
+ + +
+ ); +}; + +const SidebarSubTabs: React.FC = ({ + subTab, + tabValue, + isClickable = false, +}) => { + const { setActiveSubTab, activeSubTab } = + useContext( + ChatAndNotificationMainContext + ); + const { setSearchedChats, setSelectedChatId } = + useContext(ChatMainStateContext); + const { setSearchedNotifications } = useContext( + NotificationMainStateContext + ); + + return ( + { + if (isClickable) { + setActiveSubTab(tabValue); + if (activeSubTab === PUSH_SUB_TABS.REQUESTS) { + setSearchedChats(null); + setSelectedChatId(null); + } else if (activeSubTab === PUSH_SUB_TABS.SPAM) { + setSearchedNotifications(null); + } + } + }} + > + + {subTab.icon} + +
+ + {subTab.title} + + + {subTab.subTitle} + +
+
+ ); +}; + +export const Sidebar = () => { + const { loading: chatsLoading } = useFetchChats(); + const { fetchChat } = useFetchChat(); + + const { newChat, setNewChat, activeTab, activeSubTab } = + useContext( + ChatAndNotificationMainContext + ); + + const { + chatsFeed, + requestsFeed, + searchedChats, + web3NameList, + selectedChatId, + setSearchedChats, + } = useContext(ChatMainStateContext); + + const { env } = useContext(ChatAndNotificationPropsContext); + const { + spamNotifsFeed, + allInboxNotifFeed, + setSearchedNotifications, + searchedNotifications, + } = useContext(NotificationMainStateContext); + const { fetchChatProfile } = useGetChatProfile(); + type PushSubTabDetailsType = { + [key in PushSubTabs]: { + title: string; + subTitle: string; + icon: any; + }; + }; + const PushSubTabDetails: PushSubTabDetailsType = { + REQUESTS: { + title: PushSubTabTitle.REQUESTS.title, + subTitle: ` ${shortenNumber( + Object.keys(requestsFeed || {}).length, + 10 + )} requests from people you may know`, + icon: , + }, + SPAM: { + title: PushSubTabTitle.SPAM.title, + subTitle: `${shortenNumber( + Object.keys(spamNotifsFeed || {}).length, + 5 + )} messages in your spam box`, + icon: , + }, + }; + type handleSearchType = { + searchedText: string; + feed: ChatFeedsType | NotificationFeedsType; + }; + const handleChatSearch = async ({ searchedText, feed }: handleSearchType) => { + const result = getObjectsWithMatchingKeys( + feed as ChatFeedsType, + searchedText, + web3NameList + ); + if (Object.keys(result || {}).length) setSearchedChats(result); + else { + // const address = await getAddress(searchedText, env); + let newChatFeed; + const newChatUser = await getNewChatUser({ + searchText: searchedText, + fetchChatProfile, + env, + }); + + if (newChatUser) { + newChatFeed = (await fetchChat({ + recipientAddress: newChatUser!.did, + })) as IFeeds; + if (!Object.keys(newChatFeed || {}).length) + { + newChatFeed = getDefaultFeedObject({ user: newChatUser }); + setSearchedChats({ [newChatFeed.did.toLowerCase()]: newChatFeed }); + setNewChat(true); + } + else{ + setSearchedChats({ [newChatFeed.did.toLowerCase()]: newChatFeed }); + } + } + else{ + if (!Object.keys(newChatFeed || {}).length) { + setSearchedChats({}); + } + } + + + } + }; + const onChatSearchReset = () => { + setSearchedChats(null); + }; + const handleNotifSearch = async ({ + searchedText, + feed, + }: handleSearchType) => { + const result = getSearchedNotificationsList( + searchedText, + feed as NotificationFeedsType + ); + setSearchedNotifications(result); + }; + return ( +
+ {!newChat && } + + {activeSubTab !== PUSH_SUB_TABS.REQUESTS && + (activeTab === PUSH_TABS.CHATS || newChat) && ( + + )} + + {activeSubTab !== PUSH_SUB_TABS.SPAM && + activeTab === PUSH_TABS.APP_NOTIFICATIONS && + !newChat && ( + setSearchedNotifications(null)} + placeholder="Search Notification" + /> + )} + + {!searchedChats && newChat && ( + + )} + {!newChat && + !chatsLoading && + !searchedChats && + activeTab === PUSH_TABS.CHATS && ( + <> + + {activeSubTab !== PUSH_SUB_TABS.REQUESTS && } + + )} + {!newChat && + !searchedNotifications && + activeTab === PUSH_TABS.APP_NOTIFICATIONS && ( + <> + + {activeSubTab !== PUSH_SUB_TABS.SPAM && ( + + )} + + )} + {(activeTab === PUSH_TABS.CHATS || newChat) && ( + <> + + {searchedChats && !!Object.keys(searchedChats).length && ( + + )} + + {searchedChats && !Object.keys(searchedChats).length && ( + + )} + + )} + + {activeTab === PUSH_TABS.APP_NOTIFICATIONS && !newChat && ( + <> + + {searchedNotifications && + !!Object.keys(searchedNotifications).length && ( + + )} + + {searchedNotifications && + !Object.keys(searchedNotifications).length && ( + + )} + + )} +
+ ); +}; + +//styles +const SubContainer = styled(Section)` + border-bottom: 1px dashed #ededee; + cursor: pointer; + &:hover { + background: #f4f5fa; + } +`; +const ChatListCard = styled(Section)` + &::-webkit-scrollbar-thumb { + background: rgb(181 181 186); + border-radius: 10px; + } + + &::-webkit-scrollbar { + width: 5px; + } +`; + +const NotificationListCard = styled(Div)` + overflow: hidden auto; + padding: 0 1px; + &::-webkit-scrollbar-thumb { + background: rgb(181 181 186); + border-radius: 10px; + } + + &::-webkit-scrollbar { + width: 5px; + } +`; + +const TabTitleSpan = styled(Span)` + @media ${device.mobileL} { + font-size: 14px; + } +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/SidebarPlaceholder.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/SidebarPlaceholder.tsx new file mode 100644 index 000000000..8143b444e --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/SidebarPlaceholder.tsx @@ -0,0 +1,62 @@ +import { NewMessage } from '../../../../icons/NewMessage'; +import { SearchIcon } from '../../../../icons/Search'; +import type { SidebarPlaceholderKeys } from '../../../../types'; +import React from 'react'; +import { Section, Span } from '../../../reusables'; + +type SidebarPlaceholderPropsType = { + id: SidebarPlaceholderKeys; +}; + +const SidebarPlaceholderContent = { + SEARCH: { + title: 'No Results', + subTitle: '', + IconComponent: , + }, + NEW_CHAT: { + title: 'Start a new chat', + subTitle: 'Start by searching for a domain or wallet address.', + IconComponent: , + }, + NOTIFICATION: { + title: 'No message from apps yest', + subTitle: + 'Keep an eye out for upcoming messages from the apps you connect with.', + IconComponent: , + }, + CHAT: { + title: 'Start your first chat', + subTitle: 'Get started by messaging a friend.', + IconComponent: , + }, +}; +export const SidebarPlaceholder: React.FC = ({ id }) => { + return ( +
+ {SidebarPlaceholderContent[id].IconComponent} +
+ + {SidebarPlaceholderContent[id].title} + + + {SidebarPlaceholderContent[id].subTitle} + +
+
+ ); +}; + diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatList.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatList.tsx new file mode 100644 index 000000000..52ab339a3 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatList.tsx @@ -0,0 +1,25 @@ +import type { ChatFeedsType } from '../../../../../types'; +import React, { useContext } from 'react'; +import { ChatSnap } from './ChatSnap'; +import { ChatAndNotificationMainContext } from '../../../../../context'; +import type { ChatAndNotificationMainContextType } from '../../../../../context/chatAndNotification/chatAndNotificationMainContext'; + +type ChatListPropType = { + chatsFeed: ChatFeedsType; +}; + +export const ChatList: React.FC = ({ chatsFeed }) => { + const { activeTab } = useContext(ChatAndNotificationMainContext) + + return ( + <> + {!!Object.keys(chatsFeed || {}).length && + Object.keys(chatsFeed).map((id: string) => ( + + ))} + + ); +}; + +//styles + diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatSnap.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatSnap.tsx new file mode 100644 index 000000000..a5b285906 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatSnap.tsx @@ -0,0 +1,188 @@ +import type { IFeeds } from '@pushprotocol/restapi'; +import { + ChatMainStateContext, + ChatAndNotificationPropsContext, +} from '../../../../../context'; +import { + checkIfUnread, + dateToFromNowDaily, + setData, + shortenText, +} from '../../../../../helpers'; +import React, { useContext } from 'react'; +import styled, { css } from 'styled-components'; +import { Section, Span, Image } from '../../../../reusables/sharedStyling'; +import { UnreadChats } from '../../../MinimisedModalHeader'; +import { pCAIP10ToWallet } from '../../../../../helpers'; +import { ethers } from 'ethers'; +import { useResolveWeb3Name } from '../../../../../hooks'; +import { device } from '../../../../../config'; +import type { ChatMainStateContextType } from '../../../../../context/chatAndNotification/chat/chatMainStateContext'; +import { useDeviceWidthCheck } from '../../../../../hooks'; + +type ChatSnapPropType = { + chat: IFeeds; + id: string; + modalOpen?: boolean; +}; + +//fix messageType type +const Message = ({ + messageContent, + messageType, +}: { + messageContent: string; + messageType: string; +}) => { + const isMobile = useDeviceWidthCheck(425); + const digitsToDisplay = isMobile ? 27 : 48; + return messageType === 'Text' ? ( + + {shortenText(messageContent, digitsToDisplay)} + + ) : messageType === 'Image' ? ( + + Image + + ) : messageType === 'File' ? ( + + File + + ) : messageType === 'GIF' || messageType === 'MediaEmbed' ? ( + + Media + + ) : null; +}; + +export const ChatSnap: React.FC = ({ + chat, + id, + modalOpen, +}) => { + const { setSelectedChatId, web3NameList } = + useContext(ChatMainStateContext); + const { env } = useContext(ChatAndNotificationPropsContext); + + const isMobile = useDeviceWidthCheck(425); + const digitsToDisplay = chat?.name ? (isMobile ? 15 : 30) : isMobile ? 6 : 8; + + useResolveWeb3Name(chat?.did, env); + //shift to helper + const walletLowercase = pCAIP10ToWallet(chat?.did)?.toLowerCase(); + const checksumWallet = walletLowercase + ? ethers.utils.getAddress(walletLowercase) + : null; + const web3Name = checksumWallet + ? web3NameList[checksumWallet.toLowerCase()] + : null; + const handleOnClick = () => { + setSelectedChatId(id); + setData({ chatId: id, value: chat }); + }; + const open = modalOpen === undefined ? true : modalOpen; + return ( + handleOnClick()} + active={open} + gap="18px" + cursor="pointer" + > + profile picture +
+
+ + {chat?.name + ? shortenText(chat?.name, digitsToDisplay, false) + : web3Name ?? + shortenText(chat?.did?.split(':')[1], digitsToDisplay, true)} + + {open && + {chat?.msg?.timestamp + ? dateToFromNowDaily(chat?.msg?.timestamp as number) + : ''} + } +
+ + +
+ + + {open && checkIfUnread(id, chat) && ( + + )} +
+ +
+
+ ); +}; + +//styles +const Container = styled(Section)<{ active: boolean }>` + border-bottom: ${(props) => props.active && '1px dashed #ededee'}; + cursor: ${(props) => props.active && 'pointer'}; + + ${(props: any) => + props.active && + css` + &:hover { + background: #f4f5fa; + border-radius: 10px; + } + `}; +`; + +const NameSpan = styled(Span)` + font-size: 16px; + @media ${device.mobileL} { + font-size: 14px; + } +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatsFeedList.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatsFeedList.tsx new file mode 100644 index 000000000..a20bd8fe4 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatsFeedList.tsx @@ -0,0 +1,120 @@ +import useFetchChats from '../../../../../hooks/chat/useFetchChats'; +import React, { useEffect, useState, useContext, useRef } from 'react'; +import styled from 'styled-components'; + +import { + ChatMainStateContext, + ChatAndNotificationPropsContext, +} from '../../../../../context'; +import { ChatList } from './ChatList'; +import { Section } from '../../../../reusables/sharedStyling'; +import { Spinner } from '../../../../reusables/Spinner'; +import { chatLimit } from '../../../../../config'; +import type { ChatFeedsType } from '../../../../../types'; +import { SIDEBAR_PLACEHOLDER_KEYS } from '../../../../../types'; +import { useIsInViewport } from '../../../../../hooks'; +import { SidebarPlaceholder } from '../SidebarPlaceholder'; +import type { ChatMainStateContextType } from '../../../../../context/chatAndNotification/chat/chatMainStateContext'; + +export const ChatsFeedList = () => { + const { chatsFeed, setChatsFeed } = + useContext(ChatMainStateContext); + const pageRef = useRef(null); + const [page, setPage] = useState(1); + const [paginateLoading, setPaginateLoading] = useState(false); + const isInViewport1 = useIsInViewport(pageRef, '1px'); + const { decryptedPgpPvtKey, account, env } = useContext( + ChatAndNotificationPropsContext + ); + const { fetchChats, loading } = useFetchChats(); + + const fetchChatList = async () => { + const feeds = await fetchChats({ page, chatLimit }); + const firstFeeds: ChatFeedsType = { ...feeds }; + setChatsFeed(firstFeeds); + }; + + useEffect(() => { + if (Object.keys(chatsFeed).length) { + return; + } + if (decryptedPgpPvtKey) { + fetchChatList(); + } + }, [fetchChats, env, page, account]); + + useEffect(() => { + if ( + !isInViewport1 || + loading || + Object.keys(chatsFeed).length < chatLimit + ) { + return; + } + + const newPage = page + 1; + setPage(newPage); + // eslint-disable-next-line no-use-before-define + callFeeds(newPage); + }, [isInViewport1]); + + const callFeeds = async (page: number) => { + if (!decryptedPgpPvtKey) { + return; + } + try { + setPaginateLoading(true); + const feeds = await fetchChats({ page, chatLimit }); + const newFeed: ChatFeedsType = { ...chatsFeed, ...feeds }; + setChatsFeed(newFeed); + } catch (error) { + console.log(error); + setPaginateLoading(false); + } finally { + setPaginateLoading(false); + } + }; + + return ( + + {(!loading || paginateLoading) && Object.keys(chatsFeed || {}).length ? ( + + ) : ( + !paginateLoading && + loading && ( +
+ +
+ ) + )} + {!loading && Object.keys(chatsFeed).length === 0 && ( + + )} + +
+ + {paginateLoading && ( +
+ +
+ )} +
+ ); +}; + +//styles +const ChatListCard = styled(Section)` + padding:0px 3px 0px 0px; + &::-webkit-scrollbar-thumb { + background: rgb(181 181 186); + border-radius: 10px; + } + + &::-webkit-scrollbar { + width: 5px; + } +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/RequestsFeedList.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/RequestsFeedList.tsx new file mode 100644 index 000000000..a399adc44 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/RequestsFeedList.tsx @@ -0,0 +1,113 @@ +import useFetchRequests from '../../../../../hooks/chat/useFetchRequests'; +import React, { useEffect, useState, useContext, useRef } from 'react'; +import styled from 'styled-components'; +import { ChatMainStateContext, ChatAndNotificationPropsContext } from '../../../../../context'; +import { ChatList } from './ChatList'; +import { Section, Span } from '../../../../reusables/sharedStyling'; +import { Spinner } from '../../../../reusables/Spinner'; +import { requestLimit } from '../../../../../config'; +import type { ChatFeedsType } from '../../../../../types'; +import { useIsInViewport } from '../../../../../hooks'; +import type { ChatMainStateContextType } from '../../../../../context/chatAndNotification/chat/chatMainStateContext'; + +export const RequestsFeedList = () => { + const { requestsFeed, setRequestsFeed } = useContext(ChatMainStateContext); + const pageRef = useRef(null); + const [page, setPage] = useState(1); + const [paginateLoading, setPaginateLoading] = useState(false); + const isInViewport1 = useIsInViewport(pageRef, '1px'); + const { decryptedPgpPvtKey, env } = + useContext(ChatAndNotificationPropsContext); + const { fetchRequests, loading } = useFetchRequests(); + + const fetchRequestList = async () => { + const feeds = await fetchRequests({ page, requestLimit }); + const firstFeeds: ChatFeedsType = { ...feeds }; + setRequestsFeed(firstFeeds); + }; + + useEffect(() => { + if (Object.keys(requestsFeed).length) { + return; + } + if (decryptedPgpPvtKey) { + fetchRequestList(); + } + }, [fetchRequests, decryptedPgpPvtKey, env, page]); + + useEffect(() => { + if ( + !isInViewport1 || + loading || + Object.keys(requestsFeed).length < requestLimit + ) { + return; + } + + const newPage = page + 1; + setPage(newPage); + // eslint-disable-next-line no-use-before-define + callFeeds(newPage); + }, [isInViewport1]); + + const callFeeds = async (page: number) => { + if (!decryptedPgpPvtKey) { + return; + } + try { + setPaginateLoading(true); + const feeds = await fetchRequests({ page, requestLimit }); + const newFeed: ChatFeedsType = { ...requestsFeed, ...feeds }; + setRequestsFeed(newFeed); + } catch (error) { + console.log(error); + setPaginateLoading(false); + } finally { + setPaginateLoading(false); + } + }; + + + return ( + + {(!loading || paginateLoading) && Object.keys(requestsFeed || {}).length ? ( + + ) : ( + !paginateLoading && loading && ( +
+ +
+ ) + )} + {!loading && Object.keys(requestsFeed).length === 0 && ( + No Requests yet + )} + +
+ + {paginateLoading && ( +
+ +
+ )} +
+ ); +}; + +//styles +const ChatListCard = styled(Section)` + &::-webkit-scrollbar-thumb { + background: rgb(181 181 186); + border-radius: 10px; + } + + &::-webkit-scrollbar { + width: 5px; + } +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/InboxNotificationFeedList.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/InboxNotificationFeedList.tsx new file mode 100644 index 000000000..a41dd478f --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/InboxNotificationFeedList.tsx @@ -0,0 +1,171 @@ +import React, { useEffect, useState, useContext, useRef } from 'react'; +import styled from 'styled-components'; + +import { + ChatAndNotificationPropsContext, + NotificationMainStateContext, +} from '../../../../../context'; + +import { Div, Section } from '../../../../reusables/sharedStyling'; +import { Spinner } from '../../../../reusables/Spinner'; + +import { useIsInViewport } from '../../../../../hooks'; +import { NotificationFeedList } from './NotificationFeedList'; +import useFetchNotification from '../../../../../hooks/notifications/useFetchNotification'; +import type { + NotificationFeedsType, ParsedNotificationType} from '../../../../../types'; +import { + SIDEBAR_PLACEHOLDER_KEYS, +} from '../../../../../types'; +import { notificationLimit } from '../../../../../config'; +import { SidebarPlaceholder } from '../SidebarPlaceholder'; + +export const InboxNotificationFeedList = () => { + const { + inboxNotifsFeed, + setInboxNotifsFeed, + allInboxNotifFeed, + setAllInboxNotifsFeed, + setSpamNotifsFeed, + spamNotifsFeed, + } = useContext(NotificationMainStateContext); + const pageRef = useRef(null); + const { account, env } = useContext(ChatAndNotificationPropsContext); + const [page, setPage] = useState(1); + const [paginateLoading, setPaginateLoading] = useState(false); + const isInViewport1 = useIsInViewport(pageRef, '1px'); + const { fetchNotification, loading } = useFetchNotification(); + + + const fetchSpamNotificationList = async () => { + const feeds: NotificationFeedsType | undefined = await fetchNotification({ + page: 1, + limit: notificationLimit, + spam: true, + }); + //change type of notification + if (feeds) { + const firstFeeds: NotificationFeedsType = { ...feeds }; + setSpamNotifsFeed(firstFeeds); + } + }; + + useEffect(() => { + if (Object.keys(spamNotifsFeed).length) { + return; + } + fetchSpamNotificationList(); + }, [env, account]); + + const fetchInboxNotificationList = async () => { + const feeds: NotificationFeedsType | undefined = await fetchNotification({ + page: 1, + limit: notificationLimit, + }); + //change type of notification + if (feeds) { + const firstFeeds: NotificationFeedsType = { ...feeds }; + setInboxNotifsFeed(firstFeeds); + } + }; + useEffect(() => { + if (Object.keys(inboxNotifsFeed).length) { + return; + } + if (account) { + fetchInboxNotificationList(); + } + }, [fetchNotification, env, page, account]); + + useEffect(() => { + if (Object.keys(allInboxNotifFeed).length) { + return; + } + if (account) { + (async () => { + const feeds = await fetchNotification({ page, limit: 10000 }); + setAllInboxNotifsFeed({ ...feeds }); + })(); + } + }, [fetchNotification, env, page, account]); + + useEffect(() => { + if ( + !isInViewport1 || + loading + || + Object.keys(inboxNotifsFeed).length < notificationLimit + ) { + return; + } + + const newPage = page + 1; + setPage(newPage); + // eslint-disable-next-line no-use-before-define + callFeeds(newPage); + }, [isInViewport1]); + + const callFeeds = async (page: number) => { + if (!account) { + return; + } + try { + setPaginateLoading(true); + const feeds = await fetchNotification({ page, limit: notificationLimit }); + const newFeed:NotificationFeedsType = {...inboxNotifsFeed,...feeds}; + + setInboxNotifsFeed(newFeed); + } catch (error) { + console.log(error); + setPaginateLoading(false); + } finally { + setPaginateLoading(false); + } + }; + + return ( + + {(!loading || paginateLoading) && + Object.keys(inboxNotifsFeed || {}).length ? ( +
+ +
+ ) : ( + !paginateLoading && + loading && ( +
+ +
+ ) + )} + {!loading && Object.keys(inboxNotifsFeed).length === 0 && ( + + )} + +
+ + {paginateLoading && ( +
+ +
+ )} +
+ ); +}; + +//styles +const InboxNotifListCard = styled(Section)` + &::-webkit-scrollbar-thumb { + background: rgb(181 181 186); + border-radius: 10px; + } + + &::-webkit-scrollbar { + width: 5px; + } +`; diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/NotificationFeedList.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/NotificationFeedList.tsx new file mode 100644 index 000000000..df0aba849 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/NotificationFeedList.tsx @@ -0,0 +1,89 @@ +import type { NotificationFeedsType } from '../../../../../types'; +import React, { useContext } from 'react'; +import type { chainNameType, INotificationItemTheme} from '../../../../notification'; +import { notificationLightTheme } from '../../../../notification'; +import { NotificationItem } from '../../../../notification'; +import { ChatAndNotificationPropsContext, NotificationMainStateContext } from '../../../../../context'; +import useOnSubscribeToChannel from '../../../../../hooks/notifications/useOnSubscribeToChannel'; +import { Div } from '../../../../reusables'; + +type NotificationFeedListPropType = { + notificationFeeds: NotificationFeedsType; +}; +const customTheme: INotificationItemTheme = {...notificationLightTheme,...{ + borderRadius:{ + ...notificationLightTheme.borderRadius, + modal:'12px', + }, + color:{ + ...notificationLightTheme.color, + channelNameText:'#62626A', + notificationTitleText:'#000', + notificationContentText:'#62626A', + modalBorder:'#C8C8CB', + timestamp:'#62626A', + }, + fontWeight:{ + ...notificationLightTheme.fontWeight, + channelNameText:600, + notificationTitleText:600, + notificationContentText:500, + timestamp:400 + }, + fontSize:{ + ...notificationLightTheme.fontSize, + channelNameText:'16px', + notificationTitleText:'16px', + notificationContentText:'16px', + timestamp:'12px' + }, + modalDivider:'none' +}}; + +export const NotificationFeedList: React.FC = ({ + notificationFeeds, +}) => { + const { subscriptionStatus } = useContext(NotificationMainStateContext); + const { onSubscribeToChannel } = useOnSubscribeToChannel(); + const { signer} = useContext(ChatAndNotificationPropsContext); + const isSubscribedFn = (channel: string) => { + return subscriptionStatus.get(channel); + }; + return ( + <> + {!!Object.keys(notificationFeeds || {}).length && + Object.keys(notificationFeeds).map((id: string) => ( + + onSubscribeToChannel({ + channelAddress: notificationFeeds[id].channel, + }) + : undefined + } + isSubscribedFn={ + (!!signer&& !subscriptionStatus.get(notificationFeeds[id].channel)) + ? async () => isSubscribedFn(notificationFeeds[id].channel) + : undefined + } + chainName={notificationFeeds[id].blockchain as chainNameType} + url={notificationFeeds[id].url} + /> + ))} + + + ); +}; + +//styles diff --git a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/SpamNotificationFeedList.tsx b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/SpamNotificationFeedList.tsx new file mode 100644 index 000000000..8c2543c42 --- /dev/null +++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/SpamNotificationFeedList.tsx @@ -0,0 +1,133 @@ +import React, { useEffect, useState, useContext, useRef } from 'react'; +import styled from 'styled-components'; + +import { + ChatAndNotificationPropsContext, + NotificationMainStateContext, +} from '../../../../../context'; + +import { Div, Section, Span } from '../../../../reusables/sharedStyling'; +import { Spinner } from '../../../../reusables/Spinner'; + +import { useIsInViewport } from '../../../../../hooks'; +import { NotificationFeedList } from './NotificationFeedList'; +import { notificationLimit } from '../../../../../config'; +import type { NotificationFeedsType } from '../../../../../types'; +import useFetchNotification from '../../../../../hooks/notifications/useFetchNotification'; + +export const SpamNotificationFeedList = () => { + const { spamNotifsFeed, setSpamNotifsFeed } = useContext( + NotificationMainStateContext + ); + const pageRef = useRef(null); + const { account, env } = useContext(ChatAndNotificationPropsContext); + const [page, setPage] = useState(1); + const [paginateLoading, setPaginateLoading] = useState(false); + const isInViewport1 = useIsInViewport(pageRef, '1px'); + const { fetchNotification, loading } = useFetchNotification(); + + const fetchSpamNotificationList = async () => { + const feeds: NotificationFeedsType | undefined = await fetchNotification({ + page: 1, + limit: notificationLimit, + spam: true, + }); + if (feeds) { + const firstFeeds: NotificationFeedsType = { ...feeds }; + setSpamNotifsFeed(firstFeeds); + } + }; + + useEffect(() => { + if (Object.keys(spamNotifsFeed).length) { + return; + } + fetchSpamNotificationList(); + }, [env, account]); + + useEffect(() => { + if ( + !isInViewport1 || + loading || + Object.keys(spamNotifsFeed).length < notificationLimit + ) { + return; + } + + const newPage = page + 1; + + setPage(newPage); + // eslint-disable-next-line no-use-before-define + callFeeds(newPage); + }, [isInViewport1]); + + const callFeeds = async (page: number) => { + if (!account) { + return; + } + try { + setPaginateLoading(true); + const feeds = await fetchNotification({ + page, + limit: notificationLimit, + spam: true, + }); + const newFeed: NotificationFeedsType = { ...spamNotifsFeed, ...feeds }; + + + setSpamNotifsFeed(newFeed); + } catch (error) { + console.log(error); + setPaginateLoading(false); + } finally { + setPaginateLoading(false); + } + }; + + return ( + + {(!loading || paginateLoading) && + Object.keys(spamNotifsFeed || {}).length ? ( +
+ +
+ ) : ( + !paginateLoading && + loading && ( +
+ +
+ ) + )} + {!loading && Object.keys(spamNotifsFeed).length === 0 && ( + No messages from apps yet + )} +
+ + {paginateLoading && ( +
+ +
+ )} +
+ ); +}; + +//styles +const SpamNotifListCard = styled(Section)` + &::-webkit-scrollbar-thumb { + background: rgb(181 181 186); + border-radius: 10px; + } + + &::-webkit-scrollbar { + width: 5px; + } +`; diff --git a/packages/uiweb/src/lib/components/index.ts b/packages/uiweb/src/lib/components/index.ts index 1f6eaf4d3..e0e0c0686 100644 --- a/packages/uiweb/src/lib/components/index.ts +++ b/packages/uiweb/src/lib/components/index.ts @@ -1,4 +1,5 @@ export * from './notification'; export * from './parsetext'; export * from './subscribemodal'; -export * from './chat'; \ No newline at end of file +export * from './supportChat'; +export * from './chatAndNotification'; \ No newline at end of file diff --git a/packages/uiweb/src/lib/components/notification/chainDetails.tsx b/packages/uiweb/src/lib/components/notification/chainDetails.tsx index 789c50b52..ad783c516 100644 --- a/packages/uiweb/src/lib/components/notification/chainDetails.tsx +++ b/packages/uiweb/src/lib/components/notification/chainDetails.tsx @@ -1,28 +1,62 @@ -import EthereumSVG from "../../icons/ethereum.svg"; -import PolygonSVG from "../../icons/polygon.svg"; -import GraphSVG from "../../icons/thegraph.svg"; + import Tooltip from "../tooltip"; -import BscSVG from "../../icons/bsc.svg"; -import OptimismSVG from "../../icons/optimism.svg"; -import PolygonZKEVMSvg from "../../icons/polygonzkevm.svg" -const createSVGIcon = (url: string, chainName: string) => { + +import { EthereumSvg } from '../../icons/EthereumSvg'; +import { PolygonSvg } from "../../icons/PolygonSvg"; +import { BSCSvg } from "../../icons/BSCSvg"; +import { OptimismSvg } from "../../icons/OptimismSvg"; +import { PolygonzkevmSvg } from "../../icons/PolygonzkevmSvg"; +import { TheGraphSvg } from "../../icons/TheGraphSvg"; +import { ReactElement } from "react"; + +const createSVGIcon = (element:any, chainName: string) => { return ( - {chainName.toUpperCase()} + {element} - ) -} + ); +}; export default { - ETH_TEST_GOERLI: { label: "ETHEREUM GOERLI", icon: createSVGIcon(EthereumSVG, "Ethereum Goerli") }, - ETH_MAINNET: { label: "ETHEREUM MAINNET", icon: createSVGIcon(EthereumSVG, "Ethereum Mainnet") }, - POLYGON_TEST_MUMBAI: { label: "POLYGON MUMBAI", icon: createSVGIcon(PolygonSVG, "Polygon Mumbai") }, - POLYGON_MAINNET: { label: "POLYGON MAINNET", icon: createSVGIcon(PolygonSVG, "Polygon Mainnet") }, - BSC_TESTNET: { label: "BSC TESTNET", icon: createSVGIcon(BscSVG, "Bsc Testnet") }, - BSC_MAINNET: { label: "BSC MAINNET", icon: createSVGIcon(BscSVG, "Bsc Mainnet") }, - OPTIMISM_TESTNET: { label: "OPTIMISM TESTNET", icon: createSVGIcon(OptimismSVG, "Optimism Testnet") }, - OPTIMISM_MAINNET: { label: "OPTIMISM MAINNET", icon: createSVGIcon(OptimismSVG, "Optimism Mainnet") }, - POLYGON_ZK_EVM_TESTNET: { label: "POLYGON ZK EVM TESTNET", icon: createSVGIcon(PolygonZKEVMSvg, "Polygon ZK EVM Testnet") }, - POLYGON_ZK_EVM_MAINNET: { label: "POLYGON ZK EVM MAINNET", icon: createSVGIcon(PolygonZKEVMSvg, "Polygon ZK EVM Mainnet") }, - THE_GRAPH: { label: "THE GRAPH", icon: createSVGIcon(GraphSVG, "The Graph") }, + ETH_TEST_GOERLI: { + label: 'ETHEREUM GOERLI', + icon: createSVGIcon(, 'Ethereum Goerli'), + }, + ETH_MAINNET: { + label: 'ETHEREUM MAINNET', + icon: createSVGIcon(, 'Ethereum Mainnet'), + }, + POLYGON_TEST_MUMBAI: { + label: 'POLYGON MUMBAI', + icon: createSVGIcon(, 'Polygon Mumbai'), + }, + POLYGON_MAINNET: { + label: 'POLYGON MAINNET', + icon: createSVGIcon(, 'Polygon Mainnet'), + }, + BSC_TESTNET: { + label: 'BSC TESTNET', + icon: createSVGIcon(, 'Bsc Testnet'), + }, + BSC_MAINNET: { + label: 'BSC MAINNET', + icon: createSVGIcon(, 'Bsc Mainnet'), + }, + OPTIMISM_TESTNET: { + label: 'OPTIMISM TESTNET', + icon: createSVGIcon(, 'Optimism Testnet'), + }, + OPTIMISM_MAINNET: { + label: 'OPTIMISM MAINNET', + icon: createSVGIcon(, 'Optimism Mainnet'), + }, + POLYGON_ZK_EVM_TESTNET: { + label: 'POLYGON ZK EVM TESTNET', + icon: createSVGIcon(, 'Polygon ZK EVM Testnet'), + }, + POLYGON_ZK_EVM_MAINNET: { + label: 'POLYGON ZK EVM MAINNET', + icon: createSVGIcon(, 'Polygon ZK EVM Mainnet'), + }, + THE_GRAPH: { label: 'THE GRAPH', icon: createSVGIcon(, 'The Graph') }, }; diff --git a/packages/uiweb/src/lib/components/notification/index.tsx b/packages/uiweb/src/lib/components/notification/index.tsx index ca65ab0d9..8046d74a2 100644 --- a/packages/uiweb/src/lib/components/notification/index.tsx +++ b/packages/uiweb/src/lib/components/notification/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import IPFSIcon from '../ipfsicon'; import ImageOverlayComponent from '../overlay'; @@ -15,8 +15,11 @@ import ActionButton from './styled/ActionButton'; import { useDecrypt, DecryptButton } from './decrypt'; import chainDetails from './chainDetails'; -import LinkSVG from '../../icons/link.svg'; -import { getCustomTheme, INotificationItemTheme, lightTheme } from './theme'; +import { LinkIcon } from "../../icons/Link"; +import { useDivOffsetWidth } from "../../hooks"; + +import type { INotificationItemTheme} from './theme'; +import { getCustomTheme, lightTheme } from './theme'; export {lightTheme as notificationLightTheme,darkTheme as notificationDarkTheme,baseTheme as notificationBaseTheme,INotificationItemTheme} from './theme'; // ================= Define types export type chainNameType = @@ -44,7 +47,7 @@ export type NotificationItemProps = { isSpam?: boolean; subscribeFn?: () => Promise; isSubscribedFn?: () => Promise; - theme: string | undefined; + theme?: string | undefined; customTheme?: INotificationItemTheme | undefined; chainName: chainNameType; isSecret?: boolean; @@ -58,6 +61,9 @@ export type NotificationItemProps = { type ContainerDataType = { timestamp?: string; +}& OffsetWidthType; +type OffsetWidthType = { + offsetWidth: number; }; type CustomThemeProps = { @@ -113,7 +119,8 @@ export const NotificationItem: React.FC = ({ const [imageOverlay, setImageOverlay] = React.useState(''); const [subscribeLoading, setSubscribeLoading] = React.useState(false); const [isSubscribed, setIsSubscribed] = React.useState(true); //use this to confirm if this is s - + const [divRef, offsetWidth] = useDivOffsetWidth(); + const showMetaInfo = isSecret || timeStamp; // console.log({ // chainName, @@ -173,38 +180,39 @@ export const NotificationItem: React.FC = ({ }, [isSubscribedFn, isSpam]); if (isSubscribed && isSpam) return null; - // render return ( - + {/* header that only pops up on small devices */} - - - + + + {app} {chainName && chainDetails[chainName] ? ( - {chainDetails[chainName].icon} + {chainDetails[chainName].icon} ) : null} {/* header that only pops up on small devices */} {/* content of the component */} - + {/* section for media content */} {notifImage && // if its an image then render this (!MediaHelper.isMediaSupportedVideo(notifImage) ? ( setImageOverlay(notifImage || '')} @@ -213,7 +221,8 @@ export const NotificationItem: React.FC = ({ ) : // if its a youtube url, RENDER THIS MediaHelper.isMediaYoutube(notifImage) ? ( - +