diff --git a/packages/demoreact/src/app/NotificationsTest.tsx b/packages/demoreact/src/app/NotificationsTest.tsx
index 26eef90ec..5cb12858f 100644
--- a/packages/demoreact/src/app/NotificationsTest.tsx
+++ b/packages/demoreact/src/app/NotificationsTest.tsx
@@ -111,7 +111,7 @@ const NotificationsTest = () => {
});
setSpams(spams);
-
+
} catch (e) {
console.error(e);
} finally {
@@ -146,12 +146,12 @@ const NotificationsTest = () => {
Notifications Test page
{/* */}
-
+
{theme === 'dark' ? : }
-
+
{ setViewType('notif') }}>Notifications
{ setViewType('spam') }}>Spam
@@ -170,8 +170,8 @@ const NotificationsTest = () => {
{notifs ? (
{notifs.map((oneNotification, i) => {
-
- const {
+
+ const {
cta,
title,
message,
@@ -215,7 +215,7 @@ const NotificationsTest = () => {
{spams ? (
{spams.map((oneNotification, i) => {
- const {
+ const {
cta,
title,
message,
@@ -259,4 +259,4 @@ const NotificationsTest = () => {
);
}
-export default NotificationsTest;
\ No newline at end of file
+export default NotificationsTest;
diff --git a/packages/demoreact/src/app/SpaceUITest/SpaceFeed.tsx b/packages/demoreact/src/app/SpaceUITest/SpaceFeed.tsx
index 5b204b591..0e27bc11f 100644
--- a/packages/demoreact/src/app/SpaceUITest/SpaceFeed.tsx
+++ b/packages/demoreact/src/app/SpaceUITest/SpaceFeed.tsx
@@ -1,6 +1,7 @@
-import React, { useState } from 'react';
+import React, { useContext, useState } from 'react';
import { useSpaceComponents } from './useSpaceComponents';
import { Checkbox } from '../components/Checkbox';
+import { AccountContext } from '../context';
export const SpaceFeed = () => {
const { SpaceFeedComponent } = useSpaceComponents();
@@ -10,6 +11,7 @@ export const SpaceFeed = () => {
const [width, setWidth] = useState();
const [height, setHeight] = useState(500);
const [sortingOrder, setSortingOrder] = useState([]);
+ const { setSpaceId } = useContext(AccountContext);
const handleShowTab = () => {
setShowTab(!showTab);
@@ -78,6 +80,7 @@ export const SpaceFeed = () => {
height={height}
onBannerClickHandler={(spaceId: string) => {
console.log('spaceId: ', spaceId);
+ setSpaceId(spaceId);
}}
/>
>
diff --git a/packages/demoreact/src/app/SpaceUITest/SpaceWidget.tsx b/packages/demoreact/src/app/SpaceUITest/SpaceWidget.tsx
index 1bb487857..1aed3664d 100644
--- a/packages/demoreact/src/app/SpaceUITest/SpaceWidget.tsx
+++ b/packages/demoreact/src/app/SpaceUITest/SpaceWidget.tsx
@@ -139,11 +139,14 @@ export const SpaceWidget = () => {
- {
- const { spaceUI } = useSpaceComponents();
const customtheme = {
- statusColorError: 'red',
- }
+ titleBg: 'linear-gradient(45deg, #E165EC 0.01%, #A483ED 100%)', //not changed
+ titleTextColor: '#FFFFFF',
+ bgColorPrimary: '#fff',
+ bgColorSecondary: '#F7F1FB',
+ textColorPrimary: '#000',
+ textColorSecondary: '#657795',
+ textGradient: 'linear-gradient(45deg, #B6A0F5, #F46EF6, #FFDED3, #FFCFC5)', //not changed
+ btnColorPrimary: '#D53A94',
+ btnOutline: '#D53A94',
+ borderColor: '#FFFF',
+ borderRadius: '17px',
+ containerBorderRadius: '12px',
+ statusColorError: '#E93636',
+ statusColorSuccess: '#30CC8B',
+ iconColorPrimary: '#82828A',
+ };
+
+ const customDarkTheme = {
+ titleBg:
+ 'linear-gradient(87.17deg, #EA4EE4 0%, #D23CDF 0.01%, #8B5CF6 100%)',
+ titleTextColor: '#fff',
+ bgColorPrimary: '#000',
+ bgColorSecondary: '#292344',
+ textColorPrimary: '#fff',
+ textColorSecondary: '#71717A',
+ textGradient: 'linear-gradient(45deg, #B6A0F5, #F46EF6, #FFDED3, #FFCFC5)',
+ btnColorPrimary: '#8B5CF6',
+ btnOutline: '#8B5CF6',
+ borderColor: '#3F3F46',
+ borderRadius: '17px',
+ containerBorderRadius: '12px',
+ statusColorError: '#E93636',
+ statusColorSuccess: '#30CC8B',
+ iconColorPrimary: '#71717A',
+ };
return (
-
- {children}
-
+ //
+ // {children}
+ //
+ <>>
);
};
diff --git a/packages/demoreact/src/app/SpaceUITest/useSpaceComponents.tsx b/packages/demoreact/src/app/SpaceUITest/useSpaceComponents.tsx
index 5c0ee9ffc..0452683ea 100644
--- a/packages/demoreact/src/app/SpaceUITest/useSpaceComponents.tsx
+++ b/packages/demoreact/src/app/SpaceUITest/useSpaceComponents.tsx
@@ -6,12 +6,10 @@ import {
SpacesUI,
ISpaceInvitesProps,
} from '@pushprotocol/uiweb';
-import React, { useContext, useEffect, useState } from 'react';
-import { EnvContext, Web3Context } from '../context';
-import * as PushAPI from '@pushprotocol/restapi';
+import React, { useContext } from 'react';
+import { AccountContext, EnvContext, Web3Context } from '../context';
export interface IUseSpaceReturnValues {
- spaceUI: SpacesUI;
SpaceInvitesComponent: React.FC;
SpaceWidgetComponent: React.FC;
SpaceFeedComponent: React.FC;
@@ -22,39 +20,17 @@ export interface IUseSpaceReturnValues {
export const useSpaceComponents = (): IUseSpaceReturnValues => {
const { account, library } = useContext(Web3Context);
const { env } = useContext(EnvContext);
+ const { pgpPrivateKey } = useContext(AccountContext);
const librarySigner = library?.getSigner();
- const [pgpPrivateKey, setPgpPrivateKey] = useState('');
-
const spaceUI = new SpacesUI({
- account: account,
+ account: account as string,
signer: librarySigner,
pgpPrivateKey: pgpPrivateKey,
env: env,
});
- useEffect(() => {
- (async () => {
- if (!account || !env || !library) return;
-
- const user = await PushAPI.user.get({ account, env });
- let pgpPrivateKey;
- const librarySigner = await library.getSigner(account);
- if (user?.encryptedPrivateKey) {
- pgpPrivateKey = await PushAPI.chat.decryptPGPKey({
- encryptedPGPPrivateKey: user.encryptedPrivateKey,
- account,
- signer: librarySigner,
- env,
- });
- }
-
- setPgpPrivateKey(pgpPrivateKey);
- })();
- }, [account, env, library]);
-
return {
- spaceUI,
SpaceInvitesComponent: spaceUI.SpaceInvites,
SpaceWidgetComponent: spaceUI.SpaceWidget,
SpaceBannerComponent: spaceUI.SpaceBanner,
diff --git a/packages/demoreact/src/app/app.tsx b/packages/demoreact/src/app/app.tsx
index e5a51911f..279a49e41 100644
--- a/packages/demoreact/src/app/app.tsx
+++ b/packages/demoreact/src/app/app.tsx
@@ -1,11 +1,11 @@
-import { useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import { Route, Routes, Link } from 'react-router-dom';
import { useWeb3React } from '@web3-react/core';
import ConnectButton from './components/Connect';
import { Checkbox } from './components/Checkbox';
import Dropdown from './components/Dropdown';
-import { Web3Context, EnvContext, SocketContext } from './context';
+import { Web3Context, EnvContext, SocketContext, AccountContext } from './context';
import { useSDKSocket } from './hooks';
import { ReactComponent as PushLogo } from '../assets/pushLogo.svg';
import NotificationsTest from './NotificationsTest';
@@ -55,7 +55,6 @@ import GetSpacesRequestsTest from './SpaceTest/GetSpacesRequestsTest';
import GetSpacesTrendingTest from './SpaceTest/GetSpacesTrendingTest';
import SpaceUITest from './SpaceUITest/SpaceUITest';
import {
- SpacesComponentProvider,
SpaceWidget,
SpaceBanner,
SpaceFeed,
@@ -63,7 +62,9 @@ import {
SpaceInvitesComponent
} from './SpaceUITest';
import { useSpaceComponents } from './SpaceUITest/useSpaceComponents';
+import * as PushAPI from "@pushprotocol/restapi";
import { ChatWidgetTest } from './ChatWidgetTest';
+import { SpacesUI, SpacesUIProvider } from '@pushprotocol/uiweb';
window.Buffer = window.Buffer || Buffer;
@@ -147,6 +148,43 @@ const NavMenu = styled.div`
}
`;
+const customtheme = {
+ titleBg: 'linear-gradient(45deg, #E165EC 0.01%, #A483ED 100%)', //not changed
+ titleTextColor: '#FFFFFF',
+ bgColorPrimary: '#fff',
+ bgColorSecondary: '#F7F1FB',
+ textColorPrimary: '#000',
+ textColorSecondary: '#657795',
+ textGradient: 'linear-gradient(45deg, #B6A0F5, #F46EF6, #FFDED3, #FFCFC5)', //not changed
+ btnColorPrimary: '#D53A94',
+ btnOutline: '#D53A94',
+ borderColor: '#FFFF',
+ borderRadius: '17px',
+ containerBorderRadius: '12px',
+ statusColorError: '#E93636',
+ statusColorSuccess: '#30CC8B',
+ iconColorPrimary: '#82828A',
+};
+
+const customDarkTheme = {
+ titleBg:
+ 'linear-gradient(87.17deg, #EA4EE4 0%, #D23CDF 0.01%, #8B5CF6 100%)',
+ titleTextColor: '#fff',
+ bgColorPrimary: '#000',
+ bgColorSecondary: '#292344',
+ textColorPrimary: '#fff',
+ textColorSecondary: '#71717A',
+ textGradient: 'linear-gradient(45deg, #B6A0F5, #F46EF6, #FFDED3, #FFCFC5)',
+ btnColorPrimary: '#8B5CF6',
+ btnOutline: '#8B5CF6',
+ borderColor: '#3F3F46',
+ borderRadius: '17px',
+ containerBorderRadius: '12px',
+ statusColorError: '#E93636',
+ statusColorSuccess: '#30CC8B',
+ iconColorPrimary: '#71717A',
+};
+
const checkForWeb3Data = ({
library,
active,
@@ -157,17 +195,18 @@ const checkForWeb3Data = ({
};
export function App() {
- const web3Data: Web3ReactState = useWeb3React();
+ const {account, library, active, chainId} = useWeb3React();
- const [env, setEnv] = useState(ENV.PROD);
+ const [env, setEnv] = useState(ENV.DEV);
const [isCAIP, setIsCAIP] = useState(false);
const { SpaceWidgetComponent } = useSpaceComponents();
const [spaceId, setSpaceId] = useState('');
+ const [pgpPrivateKey, setPgpPrivateKey] = useState('');
const socketData = useSDKSocket({
- account: web3Data.account,
- chainId: web3Data.chainId,
+ account: account,
+ chainId: chainId,
env,
isCAIP,
});
@@ -180,6 +219,33 @@ export function App() {
setIsCAIP(!isCAIP);
};
+ useEffect(() => {
+ (async () => {
+ if (!account || !env || !library) return;
+
+ const user = await PushAPI.user.get({ account: account, env });
+ let pgpPrivateKey;
+ const librarySigner = await library.getSigner(account);
+ if (user?.encryptedPrivateKey) {
+ pgpPrivateKey = await PushAPI.chat.decryptPGPKey({
+ encryptedPGPPrivateKey: user.encryptedPrivateKey,
+ account: account,
+ signer: librarySigner,
+ env,
+ });
+ }
+
+ setPgpPrivateKey(pgpPrivateKey);
+ })();
+ }, [account, env, library]);
+
+ const spaceUI = useMemo(() => new SpacesUI({
+ account: account as string,
+ signer: library?.getSigner(),
+ pgpPrivateKey: pgpPrivateKey,
+ env: env,
+ }), [account, library, pgpPrivateKey, env]);
+
return (
@@ -211,10 +277,13 @@ export function App() {
- {checkForWeb3Data(web3Data) ? (
-
+ {checkForWeb3Data({
+ active, account, library, chainId
+ }) ? (
+
-
+
+
*/}
-
+
+
) : null}
diff --git a/packages/demoreact/src/app/context/accountContext.ts b/packages/demoreact/src/app/context/accountContext.ts
new file mode 100644
index 000000000..45750805a
--- /dev/null
+++ b/packages/demoreact/src/app/context/accountContext.ts
@@ -0,0 +1,5 @@
+import { createContext } from 'react'
+
+const AccountContext = createContext({});
+
+export default AccountContext;
\ No newline at end of file
diff --git a/packages/demoreact/src/app/context/index.ts b/packages/demoreact/src/app/context/index.ts
index cccf3958c..80db31f5d 100644
--- a/packages/demoreact/src/app/context/index.ts
+++ b/packages/demoreact/src/app/context/index.ts
@@ -1,9 +1,11 @@
import Web3Context from "./web3context";
import EnvContext from "./envContext";
import SocketContext from "./socketContext";
+import AccountContext from "./accountContext";
export {
Web3Context,
EnvContext,
- SocketContext
+ SocketContext,
+ AccountContext
};
\ No newline at end of file
diff --git a/packages/examples/sdk-backend-node/src/spaces/index.ts b/packages/examples/sdk-backend-node/src/spaces/index.ts
index f320f7659..9689045d5 100644
--- a/packages/examples/sdk-backend-node/src/spaces/index.ts
+++ b/packages/examples/sdk-backend-node/src/spaces/index.ts
@@ -55,7 +55,7 @@ export const runSpacesUseCases = async (): Promise < void > => {
╚════██║██╔═══╝ ██╔══██║██║ ██╔══╝ ╚════██║
███████║██║ ██║ ██║╚██████╗███████╗███████║
╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚══════╝╚══════╝
-
+
`)
console.log('PushAPI.user.create');
@@ -143,9 +143,9 @@ async function PushAPI_space_create(
const response = await PushAPI.space.create({
spaceName,
spaceDescription,
- members: [`eip155:${randomWallet1}`, `eip155:${randomWallet2}`],
+ listeners: [`eip155:${randomWallet1}`, `eip155:${randomWallet2}`],
spaceImage,
- admins: [],
+ speakers: [],
isPublic: true,
signer: signer,
pgpPrivateKey: pgpDecrpyptedPvtKey,
@@ -191,14 +191,14 @@ async function PushAPI_space_update(
spaceId,
spaceName,
spaceDescription,
- members: [
+ listeners: [
`eip155:${randomWallet1}`,
`eip155:${randomWallet2}`,
`eip155:${randomWallet3}`,
`eip155:${signer.address}`,
],
spaceImage,
- admins: [`eip155:${signer.address}`], // takes signer as admin automatically, add more if you want to
+ speakers: [`eip155:${signer.address}`], // takes signer as admin automatically, add more if you want to
scheduleAt: start,
scheduleEnd: end,
status: PushAPI.ChatStatus.PENDING,
@@ -255,9 +255,9 @@ async function PushAPI_space_start_and_stop(
dictionaries: [adjectives, colors, animals],
}),
spaceDescription,
- members: [`eip155:${randomWallet1}`, `eip155:${randomWallet2}`],
+ listeners: [`eip155:${randomWallet1}`, `eip155:${randomWallet2}`],
spaceImage,
- admins: [],
+ speakers: [],
isPublic: true,
signer: signer,
pgpPrivateKey: pgpDecrpyptedPvtKey,
@@ -323,9 +323,9 @@ async function PushAPI_space_approve(
dictionaries: [adjectives, colors, animals],
}),
spaceDescription,
- members: [`eip155:${randomWallet1}`, `eip155:${randomWallet2}`],
+ listeners: [`eip155:${randomWallet1}`, `eip155:${randomWallet2}`],
spaceImage,
- admins: [],
+ speakers: [],
isPublic: true,
signer: signer,
pgpPrivateKey: pgpDecrpyptedPvtKey,
@@ -621,4 +621,4 @@ async function PushAPI_space_trending(silent = !showAPIResponse) {
if (!silent) {
console.log(response);
}
-}
\ No newline at end of file
+}
diff --git a/packages/examples/sdk-frontend/automate.sh b/packages/examples/sdk-frontend/automate.sh
new file mode 100755
index 000000000..5d58755d8
--- /dev/null
+++ b/packages/examples/sdk-frontend/automate.sh
@@ -0,0 +1,31 @@
+#! /bin/bash
+
+who=$(whoami)
+echo "Hey, $who!"
+
+sleep 1
+
+delnode=$(rm -rf node_modules/)
+sleep 1
+echo "Node Modules Deleted."
+
+sleep 1
+
+delnext=$(rm -rf .next/)
+sleep 1
+echo ".Next Deleted"
+
+sleep 1
+
+clean=$(yarn cache clean)
+sleep 1
+echo "Yarn Cache Cleaned."
+
+sleep 1
+install=`yarn`
+sleep 1
+echo $install
+
+
+sleep 1
+echo "See you soon, $who!"
diff --git a/packages/examples/sdk-frontend/components/Spaces/useSpaceComponent.tsx b/packages/examples/sdk-frontend/components/Spaces/useSpaceComponent.tsx
index ccad60268..8797bff28 100644
--- a/packages/examples/sdk-frontend/components/Spaces/useSpaceComponent.tsx
+++ b/packages/examples/sdk-frontend/components/Spaces/useSpaceComponent.tsx
@@ -6,11 +6,11 @@ import {
SpacesUI,
ISpaceInvitesProps,
} from '@pushprotocol/uiweb';
-import { useAccount, useNetwork, useSigner } from 'wagmi';
-import React, { useContext, useEffect, useState } from 'react';
+import { useAccount, useSigner } from 'wagmi';
+import React, { useContext} from 'react';
import { ENV } from '@pushprotocol/restapi/src/lib/constants';
import * as PushAPI from '@pushprotocol/restapi';
-import { is } from 'date-fns/locale';
+import { AccountContext } from '../../contexts';
export interface IUseSpaceReturnValues {
spaceUI: SpacesUI;
@@ -24,13 +24,10 @@ export interface IUseSpaceReturnValues {
export const useSpaceComponents = (): IUseSpaceReturnValues => {
const env = ENV.DEV;
- const { address, isConnected } = useAccount();
- const { chain } = useNetwork();
+ const { address } = useAccount();
const { data: signer } = useSigner();
- const [pgpPrivateKey, setPgpPrivateKey] = useState('');
-
- console.log('address: ', address, isConnected);
+ const { pgpPrivateKey } = useContext(AccountContext);
const spaceUI = new SpacesUI({
account: address as string,
@@ -39,28 +36,6 @@ export const useSpaceComponents = (): IUseSpaceReturnValues => {
env: env,
});
- useEffect(() => {
- (async () => {
- if (!signer || !address || !chain?.id) return;
-
- const user = await PushAPI.user.get({
- account: address,
- env,
- });
- let pgpPrivateKey = null;
- if (user?.encryptedPrivateKey) {
- pgpPrivateKey = await PushAPI.chat.decryptPGPKey({
- encryptedPGPPrivateKey: user.encryptedPrivateKey,
- account: address,
- signer,
- env,
- });
- }
-
- setPgpPrivateKey(pgpPrivateKey);
- })();
- }, [address, env, signer, chain]);
-
return {
spaceUI,
SpaceInvitesComponent: spaceUI.SpaceInvites,
diff --git a/packages/examples/sdk-frontend/contexts/accountContext.ts b/packages/examples/sdk-frontend/contexts/accountContext.ts
new file mode 100644
index 000000000..45750805a
--- /dev/null
+++ b/packages/examples/sdk-frontend/contexts/accountContext.ts
@@ -0,0 +1,5 @@
+import { createContext } from 'react'
+
+const AccountContext = createContext({});
+
+export default AccountContext;
\ No newline at end of file
diff --git a/packages/examples/sdk-frontend/contexts/index.ts b/packages/examples/sdk-frontend/contexts/index.ts
new file mode 100644
index 000000000..c5064de89
--- /dev/null
+++ b/packages/examples/sdk-frontend/contexts/index.ts
@@ -0,0 +1,5 @@
+import AccountContext from "./accountContext";
+
+export {
+ AccountContext
+};
\ No newline at end of file
diff --git a/packages/examples/sdk-frontend/pages/_app.tsx b/packages/examples/sdk-frontend/pages/_app.tsx
index 6013004e0..d99c4c625 100644
--- a/packages/examples/sdk-frontend/pages/_app.tsx
+++ b/packages/examples/sdk-frontend/pages/_app.tsx
@@ -12,7 +12,9 @@ import { publicProvider } from 'wagmi/providers/public';
import '@rainbow-me/rainbowkit/styles.css';
import '../styles/globals.css';
import { useEffect, useState } from 'react';
-import { SpacesComponentProvider } from './spaces';
+import { SpacesUIProvider } from '@pushprotocol/uiweb';
+import { useSpaceComponents } from './../components/Spaces/useSpaceComponent';
+import { AccountContext } from '../contexts';
const { chains, provider } = configureChains([goerli], [publicProvider()]);
@@ -28,8 +30,27 @@ const wagmiClient = createClient({
provider,
});
+export interface ISpacesComponentProps {
+ children: React.ReactNode;
+}
+
+const SpacesComponentProvider = ({ children }: ISpacesComponentProps) => {
+ const { spaceUI } = useSpaceComponents();
+
+ const customtheme = {
+ statusColorError: 'red',
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
function MyApp({ Component, pageProps }: AppProps) {
const [loadWagmi, setLoadWagmi] = useState(false);
+ const [pgpPrivateKey, setPgpPrivateKey] = useState('');
useEffect(() => {
setLoadWagmi(true);
@@ -41,9 +62,11 @@ function MyApp({ Component, pageProps }: AppProps) {
{loadWagmi ? (
-
-
-
+
+
+
+
+
) : null}
diff --git a/packages/examples/sdk-frontend/pages/spaces/index.tsx b/packages/examples/sdk-frontend/pages/spaces/index.tsx
index 651988b8d..80cf3ae9c 100644
--- a/packages/examples/sdk-frontend/pages/spaces/index.tsx
+++ b/packages/examples/sdk-frontend/pages/spaces/index.tsx
@@ -3,34 +3,45 @@ import styled from 'styled-components';
import { Button, Container } from '..';
import Link from 'next/link';
-import { SpacesUIProvider } from '@pushprotocol/uiweb';
import { useSpaceComponents } from './../../components/Spaces/useSpaceComponent';
+import { useContext, useEffect, useState } from 'react';
+import { useAccount, useSigner } from 'wagmi';
+import * as PushAPI from '@pushprotocol/restapi';
+import { ENV } from '@pushprotocol/restapi/src/lib/constants';
+import { AccountContext } from '../../contexts';
+const Spaces: NextPage = () => {
+ const { address } = useAccount();
+ const { data: signer } = useSigner();
-export interface ISpacesComponentProps {
- children: React.ReactNode;
-}
+ const { pgpPrivateKey, setPgpPrivateKey } = useContext(AccountContext);
+ const { SpaceWidgetComponent } = useSpaceComponents();
+ const env = ENV.DEV;
-export const SpacesComponentProvider = ({
- children,
-}: ISpacesComponentProps) => {
- const { spaceUI } = useSpaceComponents();
+ useEffect(() => {
+ (async () => {
+ if (!signer || !address || pgpPrivateKey) return;
- const customtheme = {
- statusColorError: 'red',
- };
+ const user = await PushAPI.user.get({
+ account: address,
+ env,
+ });
+ let PgpPrivateKey = null;
+ if (user?.encryptedPrivateKey) {
+ PgpPrivateKey = await PushAPI.chat.decryptPGPKey({
+ encryptedPGPPrivateKey: user.encryptedPrivateKey,
+ account: address,
+ signer,
+ env,
+ });
+ }
- return (
-
- {children}
-
- );
-};
+ setPgpPrivateKey(PgpPrivateKey);
+ })();
+ }, [address, env, signer]);
-const Spaces: NextPage = () => {
- const { SpaceWidgetComponent } = useSpaceComponents();
return (
-
+
Spaces UI Test
@@ -52,17 +63,17 @@ const Spaces: NextPage = () => {
-
+
);
};
export default Spaces;
const Section = styled.div`
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: center;
- gap: 20px;
- wrap: wrap;
-}`;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ gap: 20px;
+ flex-wrap: wrap;
+`;
diff --git a/packages/restapi/README.md b/packages/restapi/README.md
index 41c86ebf8..a9e1cdaea 100644
--- a/packages/restapi/README.md
+++ b/packages/restapi/README.md
@@ -9,96 +9,96 @@ This package gives access to Push Protocol (Push Nodes) APIs. Visit [Developer D
- [How to use in your app?](#how-to-use-in-your-app)
- [Installation](#installation)
- [Import SDK](#import-sdk)
- - [About generating the "signer" object for different platforms](#about-generating-the-signer-object-for-different-platforms)
+ - [**About generating the "signer" object for different platforms**](#about-generating-the-signer-object-for-different-platforms)
- [When using in SERVER-SIDE code:](#when-using-in-server-side-code)
- [When using in FRONT-END code:](#when-using-in-front-end-code)
- - [About blockchain agnostic address format](#about-blockchain-agnostic-address-format)
+ - [**About blockchain agnostic address format**](#about-blockchain-agnostic-address-format)
- [Chat blockchain agnostic address format](#chat-blockchain-agnostic-address-format)
- - [About Push contract addresses](#about-push-contract-addresses)
+ - [**About Push contract addresses**](#about-push-contract-addresses)
- [Push core contract address](#push-core-contract-address)
- [Push communicator contract address](#push-communicator-contract-address)
- [SDK Features](#sdk-features)
- [For Notification](#for-notification)
- - [Fetching user notifications](#fetching-user-notifications)
- - [Fetching user spam notifications](#fetching-user-spam-notifications)
- - [Fetching user subscriptions](#fetching-user-subscriptions)
- - [Fetching channel details](#fetching-channel-details)
- - [Searching for channel(s)](#searching-for-channels)
- - [Opt in to a channel](#opt-in-to-a-channel)
- - [Opt out to a channel](#opt-out-to-a-channel)
- - [Sending notification](#sending-notification)
- - [Direct payload for single recipient(target)](#direct-payload-for-single-recipienttarget)
- - [Direct payload for group of recipients(subset)](#direct-payload-for-group-of-recipientssubset)
- - [Direct payload for all recipients(broadcast)](#direct-payload-for-all-recipientsbroadcast)
- - [IPFS payload for single recipient(target)](#ipfs-payload-for-single-recipienttarget)
- - [IPFS payload for group of recipients(subset)](#ipfs-payload-for-group-of-recipientssubset)
- - [IPFS payload for all recipients(broadcast)](#ipfs-payload-for-all-recipientsbroadcast)
- - [Minimal payload for single recipient(target)](#minimal-payload-for-single-recipienttarget)
- - [Minimal payload for a group of recipient(subset)](#minimal-payload-for-a-group-of-recipientsubset)
- - [Minimal payload for all recipients(broadcast)](#minimal-payload-for-all-recipientsbroadcast)
- - [Graph payload for single recipient(target)](#graph-payload-for-single-recipienttarget)
- - [Graph payload for group of recipients(subset)](#graph-payload-for-group-of-recipientssubset)
- - [Graph payload for all recipients(broadcast)](#graph-payload-for-all-recipientsbroadcast)
+ - [**Fetching user notifications**](#fetching-user-notifications)
+ - [**Fetching user spam notifications**](#fetching-user-spam-notifications)
+ - [**Fetching user subscriptions**](#fetching-user-subscriptions)
+ - [**Fetching channel details**](#fetching-channel-details)
+ - [**Searching for channel(s)**](#searching-for-channels)
+ - [**Opt in to a channel**](#opt-in-to-a-channel)
+ - [**Opt out to a channel**](#opt-out-to-a-channel)
+ - [**Sending notification**](#sending-notification)
+ - [**Direct payload for single recipient(target)**](#direct-payload-for-single-recipienttarget)
+ - [**Direct payload for group of recipients(subset)**](#direct-payload-for-group-of-recipientssubset)
+ - [**Direct payload for all recipients(broadcast)**](#direct-payload-for-all-recipientsbroadcast)
+ - [**IPFS payload for single recipient(target)**](#ipfs-payload-for-single-recipienttarget)
+ - [**IPFS payload for group of recipients(subset)**](#ipfs-payload-for-group-of-recipientssubset)
+ - [**IPFS payload for all recipients(broadcast)**](#ipfs-payload-for-all-recipientsbroadcast)
+ - [**Minimal payload for single recipient(target)**](#minimal-payload-for-single-recipienttarget)
+ - [**Minimal payload for a group of recipient(subset)**](#minimal-payload-for-a-group-of-recipientsubset)
+ - [**Minimal payload for all recipients(broadcast)**](#minimal-payload-for-all-recipientsbroadcast)
+ - [**Graph payload for single recipient(target)**](#graph-payload-for-single-recipienttarget)
+ - [**Graph payload for group of recipients(subset)**](#graph-payload-for-group-of-recipientssubset)
+ - [**Graph payload for all recipients(broadcast)**](#graph-payload-for-all-recipientsbroadcast)
- [Notification Helper Utils](#notification-helper-utils)
- - [Parsing notifications](#parsing-notifications)
+ - [**Parsing notifications**](#parsing-notifications)
- [Advanced Notifications (WIP)](#advanced-notifications-wip)
- [DEPRECATED](#deprecated)
- - [Get a channel's subscriber list of addresses](#get-a-channels-subscriber-list-of-addresses)
+ - [**Get a channel's subscriber list of addresses**](#get-a-channels-subscriber-list-of-addresses)
- [For Chat](#for-chat)
- - [Create user for chat](#create-user-for-chat)
- - [Get user data for chat](#get-user-data-for-chat)
- - [Decrypting encrypted pgp private key from user data](#decrypting-encrypted-pgp-private-key-from-user-data)
- - [Updating chat user profile](#updating-user-profile)
- - [Fetching list of user chats](#fetching-list-of-user-chats)
- - [Fetching list of user chat requests](#fetching-list-of-user-chat-requests)
- - [Fetching conversation hash between two users](#fetching-conversation-hash-between-two-users)
- - [Fetching latest chat between two users](#fetching-latest-chat-between-two-users)
- - [Fetching chat history between two users](#fetching-chat-history-between-two-users)
- - [To send a message](#to-send-a-message)
- - [To approve a chat request](#to-approve-a-chat-request)
- - [To create a group](#to-create-a-group)
- - [To create a token gated group](#to-create-a-token-gated-group)
- - [To update group details](#to-update-group-details)
- - [To update token gated group details](#to-update-token-gated-group-details)
- - [To get group details by group name](#to-get-group-details-by-group-name)
- - [To get group details by chatId](#to-get-group-details-by-chatid)
- - [Chat Helper Utils](#chat-helper-utils)
- - [Decrypting messages](#decrypting-messages)
+ - [**Create user for chat**](#create-user-for-chat)
+ - [**Get user data for chat**](#get-user-data-for-chat)
+ - [**Decrypting encrypted pgp private key from user data**](#decrypting-encrypted-pgp-private-key-from-user-data)
+ - [**Updating User Profile**](#updating-user-profile)
+ - [**Fetching list of user chats**](#fetching-list-of-user-chats)
+ - [**Fetching list of user chat requests**](#fetching-list-of-user-chat-requests)
+ - [**Fetching conversation hash between two users**](#fetching-conversation-hash-between-two-users)
+ - [**Fetching latest chat between two users**](#fetching-latest-chat-between-two-users)
+ - [**Fetching chat history between two users**](#fetching-chat-history-between-two-users)
+ - [**To send a message**](#to-send-a-message)
+ - [**To approve a chat request**](#to-approve-a-chat-request)
+ - [**To create a group**](#to-create-a-group)
+ - [**To create a token gated group**](#to-create-a-token-gated-group)
+ - [**To update group details**](#to-update-group-details)
+ - [**To update token gated group details**](#to-update-token-gated-group-details)
+ - [**To get group details by group name**](#to-get-group-details-by-group-name)
+ - [**To get group details by chatId**](#to-get-group-details-by-chatid)
+ - [**Chat Helper Utils**](#chat-helper-utils)
+ - [**Decrypting messages**](#decrypting-messages)
- [For Video](#for-video)
- - [Instance Variables](#instance-variables)
- - [peerInstance](#peerinstance)
- - [signer](#signer)
- - [chainId](#chainid)
- - [pgpPrivateKey](#pgpprivatekey)
- - [env](#env)
- - [data](#data)
- - [setData](#setdata)
- - [Methods](#methods)
- - [constructor](#constructor)
- - [create](#create)
- - [request](#request)
- - [acceptRequest](#acceptrequest)
- - [connect](#connect)
- - [disconnect](#disconnect)
- - [enableVideo](#enablevideo)
- - [enableAudio](#enableaudio)
- - [isInitiator](#isinitiator)
+ - [**Instance Variables**](#instance-variables)
+ - [**peerInstance**](#peerinstance)
+ - [**signer**](#signer)
+ - [**chainId**](#chainid)
+ - [**pgpPrivateKey**](#pgpprivatekey)
+ - [**env**](#env)
+ - [**data**](#data)
+ - [**setData**](#setdata)
+ - [**Methods**](#methods)
+ - [**constructor**](#constructor)
+ - [**create**](#create)
+ - [**request**](#request)
+ - [**acceptRequest**](#acceptrequest)
+ - [**connect**](#connect)
+ - [**disconnect**](#disconnect)
+ - [**enableVideo**](#enablevideo)
+ - [**enableAudio**](#enableaudio)
+ - [**isInitiator**](#isinitiator)
- [For Spaces](#for-spaces)
- - [To create a space](#to-create-a-space)
- - [To create a token gated space](#to-create-a-token-gated-space)
- - [To update space details](#to-update-space-details)
- - [To update token gated space details](#to-update-token-gated-space-details)
- - [To get space details by spaceId](#to-get-space-details-by-spaceId)
- - [To start a space](#to-start-a-space)
- - [To stop a space](#to-stop-a-space)
- - [To approve a space request](#to-approve-a-space-request)
- - [To add listeners to space](#to-add-listeners-to-space)
- - [To remove listeners from space](#to-remove-listeners-from-space)
- - [To add speakers to space](#to-add-speakers-to-space)
- - [To remove speakers from space](#to-remove-speakers-from-space)
- - [Fetching list of user spaces](#fetching-list-of-user-spaces)
- - [Fetching list of user space requests](#fetching-list-of-user-space-requests)
- - [Fetching list of trending spaces](#fetching-list-of-trending-spaces)
+ - [**To create a space**](#to-create-a-space)
+ - [**To create a token gated space**](#to-create-a-token-gated-space)
+ - [**To update space details**](#to-update-space-details)
+ - [**To update token gated space details**](#to-update-token-gated-space-details)
+ - [**To get space details by spaceId**](#to-get-space-details-by-spaceid)
+ - [**To start a space**](#to-start-a-space)
+ - [**To stop a space**](#to-stop-a-space)
+ - [**To approve a space request**](#to-approve-a-space-request)
+ - [**To add listeners to space**](#to-add-listeners-to-space)
+ - [**To remove listeners from space**](#to-remove-listeners-from-space)
+ - [**To add speakers to space**](#to-add-speakers-to-space)
+ - [**To remove speakers from space**](#to-remove-speakers-from-space)
+ - [**Fetching list of user spaces**](#fetching-list-of-user-spaces)
+ - [**Fetching list of user space requests**](#fetching-list-of-user-space-requests)
+ - [**Fetching list of trending spaces**](#fetching-list-of-trending-spaces)
# How to use in your app?
diff --git a/packages/restapi/src/lib/config.ts b/packages/restapi/src/lib/config.ts
index 2042dd33c..f4c6775d3 100644
--- a/packages/restapi/src/lib/config.ts
+++ b/packages/restapi/src/lib/config.ts
@@ -6,7 +6,7 @@ const { ENV } = Constants;
export const API_BASE_URL = {
[ENV.PROD]: 'https://backend.epns.io/apis',
[ENV.STAGING]: 'https://backend-staging.epns.io/apis',
- [ENV.DEV]: 'https://backend-dev.epns.io/apis',
+ [ENV.DEV]: 'http://localhost:4000/apis',
/**
* **This is for local development only**
*/
diff --git a/packages/restapi/src/lib/payloads/constants.ts b/packages/restapi/src/lib/payloads/constants.ts
index 8930689f9..a3c5d9a41 100644
--- a/packages/restapi/src/lib/payloads/constants.ts
+++ b/packages/restapi/src/lib/payloads/constants.ts
@@ -78,4 +78,11 @@ export enum SPACE_INVITE_ROLES {
SPEAKER,
}
+export enum SPACE_ROLES {
+ HOST,
+ CO_HOST,
+ SPEAKER,
+ LISTENER
+}
+
export const DEFAULT_DOMAIN = 'push.org';
diff --git a/packages/restapi/src/lib/space/Space.ts b/packages/restapi/src/lib/space/Space.ts
index 942271874..a7f16931f 100644
--- a/packages/restapi/src/lib/space/Space.ts
+++ b/packages/restapi/src/lib/space/Space.ts
@@ -12,8 +12,6 @@ import { requestToBePromoted } from './requestToBePromoted';
import { acceptPromotionRequest } from './acceptPromotionRequest';
import { rejectPromotionRequest } from './rejectPromotionRequest';
import { connectPromotor } from './connectPromotor';
-import { addSpeaker } from './addSpeaker';
-import { removeSpeaker } from './removeSpeaker';
import { join } from './join';
import { leave } from './leave';
import { stop } from './stop';
@@ -24,13 +22,28 @@ import { VideoStreamMerger } from 'video-stream-merger';
import {
ChatStatus,
EnvOptionsType,
+ LiveSpaceData,
SignerType,
- SpaceDTO,
SpaceData,
+ SpaceSpecificData,
} from '../types';
import { VIDEO_CALL_TYPE } from '../payloads/constants';
+import getLiveSpaceData from './helpers/getLiveSpaceData';
+import sendLiveSpaceData from './helpers/sendLiveSpaceData';
+import { META_ACTION } from '../types/metaTypes';
+import { broadcastRaisedHand } from './broadcastRaisedHand';
+import { onReceiveMetaMessage } from './onReceiveMetaMessage';
+import { onJoinListener } from './onJoinListener';
+import { pCAIP10ToWallet } from '../helpers';
+
+export const initLiveSpaceData: LiveSpaceData = {
+ host: null,
+ coHosts: [],
+ speakers: [],
+ listeners: [],
+};
-const initSpaceSpecificData = {
+export const initSpaceSpecificData: SpaceSpecificData = {
members: [],
pendingMembers: [],
contractAddressERC20: null,
@@ -48,9 +61,10 @@ const initSpaceSpecificData = {
scheduleEnd: null,
status: null,
inviteeDetails: {},
+ liveSpaceData: initLiveSpaceData,
};
-export const initSpaceData = {
+export const initSpaceData: SpaceData = {
...initSpaceSpecificData,
connectionData: initVideoCallData,
};
@@ -64,17 +78,13 @@ export interface SpaceConstructorType extends EnvOptionsType {
}
// declaring the Space class
- export class Space extends Video {
- /*
- - temporarily store the streamKey on the class
- - will be used by the host to cast to the stream
- */
- // protected streamKey: string | null = null;
-
+export class Space extends Video {
protected mergeStreamObject: VideoStreamMerger | null = null;
- protected spaceSpecificData: SpaceDTO;
- protected setSpaceSpecificData: (fn: (data: SpaceDTO) => SpaceDTO) => void;
+ protected spaceSpecificData: SpaceSpecificData;
+ protected setSpaceSpecificData: (
+ fn: (data: SpaceSpecificData) => SpaceSpecificData
+ ) => void;
// will be exposed and should be used from outside the class to change state
setSpaceData: (fn: (data: SpaceData) => SpaceData) => void;
@@ -96,7 +106,11 @@ export interface SpaceConstructorType extends EnvOptionsType {
pgpPrivateKey,
env,
callType: VIDEO_CALL_TYPE.PUSH_SPACE,
- onReceiveStream: (receivedStream: MediaStream) => {
+ onReceiveStream: async (
+ receivedStream: MediaStream,
+ senderAddress: string,
+ audio: boolean | null
+ ) => {
// for a space, that has started broadcast & the local peer is the host
if (
this.spaceSpecificData.status === ChatStatus.ACTIVE &&
@@ -104,6 +118,34 @@ export interface SpaceConstructorType extends EnvOptionsType {
this.data.meta.broadcast.hostAddress === this.data.local.address
) {
addToMergedStream(this.mergeStreamObject!, receivedStream);
+
+ // update live space info
+ const oldLiveSpaceData = await getLiveSpaceData({
+ localAddress: this.data.local.address,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ spaceId: this.spaceSpecificData.spaceId,
+ });
+ const updatedLiveSpaceData = produce(oldLiveSpaceData, (draft) => {
+ // TODO: Create distinction between speakers and co hosts
+ draft.speakers.push({
+ address: senderAddress,
+ audio,
+ emojiReactions: null,
+ });
+ });
+ await sendLiveSpaceData({
+ liveSpaceData: updatedLiveSpaceData,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ spaceId: this.spaceSpecificData.spaceId,
+ signer: this.signer,
+ action: META_ACTION.PROMOTE_TO_ADMIN, // TODO: Add a meta action for SPEAKER_JOINED
+ });
+ this.setSpaceSpecificData(() => ({
+ ...this.spaceSpecificData,
+ liveSpaceData: updatedLiveSpaceData,
+ }));
}
},
setData: function () {
@@ -169,7 +211,7 @@ export interface SpaceConstructorType extends EnvOptionsType {
// set the local address inside video call 'data'
this.setData((oldVideoCallData) => {
return produce(oldVideoCallData, (draft) => {
- draft.local.address = address;
+ draft.local.address = pCAIP10ToWallet(address);
});
});
@@ -178,8 +220,7 @@ export interface SpaceConstructorType extends EnvOptionsType {
// init the spaceSpecificData class variable
this.spaceSpecificData = initSpaceSpecificData;
- };
-
+ }
// adding instance methods
@@ -193,6 +234,12 @@ export interface SpaceConstructorType extends EnvOptionsType {
public start = start;
+ public onReceiveMetaMessage = onReceiveMetaMessage;
+
+ // host will call this function from socket
+ // will fire a meta message if a new listener has joined the space
+ public onJoinListener = onJoinListener;
+
// to promote a listener to a speaker/co-host
public inviteToPromote = inviteToPromote;
public acceptPromotionInvite = acceptPromotionInvite;
@@ -201,17 +248,11 @@ export interface SpaceConstructorType extends EnvOptionsType {
// listener requests to be promoted to a speaker
public requestToBePromoted = requestToBePromoted;
+ public broadcastRaisedHand = broadcastRaisedHand; // will be called by the host after receiving the request to be promoted
public acceptPromotionRequest = acceptPromotionRequest;
public connectPromotor = connectPromotor;
public rejectPromotionRequest = rejectPromotionRequest;
- /*
- - add/remove speaker to the space group as admins
- - these methods are only to be used when the space hasnt started yet
- */
- public addSpeaker = addSpeaker;
- public removeSpeaker = removeSpeaker;
-
/*
- add/remove co-host to the space group as admins
- add/remove them from the meta message
diff --git a/packages/restapi/src/lib/space/addSpeaker.ts b/packages/restapi/src/lib/space/addSpeaker.ts
deleted file mode 100644
index 37924f724..000000000
--- a/packages/restapi/src/lib/space/addSpeaker.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { EnvOptionsType } from '../types';
-import { groupDtoToSpaceDto } from '../chat/helpers';
-import { addAdmins } from '../chat/addAdmins';
-
-import type Space from './Space';
-
-export interface AddSpeakerType extends EnvOptionsType {
- address: string;
-}
-
-export async function addSpeaker(
- this: Space,
- options: AddSpeakerType
-): Promise {
- const { address } = options;
- try {
- const group = await addAdmins({
- chatId: this.spaceSpecificData.spaceId,
- admins: [address],
- signer: this.signer,
- env: this.env,
- pgpPrivateKey: this.pgpPrivateKey,
- });
-
- // update space specific data
- this.setSpaceSpecificData(() => groupDtoToSpaceDto(group));
- } catch (err) {
- console.error(
- `[Push SDK] - API - Error - API ${addSpeaker.name} -: `,
- err
- );
- throw Error(`[Push SDK] - API - Error - API ${addSpeaker.name} -: ${err}`);
- }
-}
diff --git a/packages/restapi/src/lib/space/broadcastRaisedHand.ts b/packages/restapi/src/lib/space/broadcastRaisedHand.ts
new file mode 100644
index 000000000..38c5251ea
--- /dev/null
+++ b/packages/restapi/src/lib/space/broadcastRaisedHand.ts
@@ -0,0 +1,40 @@
+import { produce } from 'immer';
+import type Space from './Space';
+import getLiveSpaceData from './helpers/getLiveSpaceData';
+import sendLiveSpaceData from './helpers/sendLiveSpaceData';
+import { META_ACTION } from '../types/metaTypes';
+
+export interface BroadcastRaisedHandType {
+ promoteeAddress: string;
+}
+
+export async function broadcastRaisedHand(
+ this: Space,
+ options: BroadcastRaisedHandType
+) {
+ const { promoteeAddress } = options || {};
+
+ // update live space info
+ const oldLiveSpaceData = await getLiveSpaceData({
+ localAddress: this.data.local.address,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ spaceId: this.spaceSpecificData.spaceId,
+ });
+ const updatedLiveSpaceData = produce(oldLiveSpaceData, (draft) => {
+ const listnerIndex = draft.listeners.findIndex(listner => listner.address === promoteeAddress);
+ draft.listeners[listnerIndex].handRaised = true;
+ });
+ await sendLiveSpaceData({
+ liveSpaceData: updatedLiveSpaceData,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ spaceId: this.spaceSpecificData.spaceId,
+ signer: this.signer,
+ action: META_ACTION.USER_INTERACTION,
+ });
+ this.setSpaceSpecificData(() => ({
+ ...this.spaceSpecificData,
+ liveSpaceData: updatedLiveSpaceData,
+ }));
+}
diff --git a/packages/restapi/src/lib/space/helpers/getLiveSpaceData.ts b/packages/restapi/src/lib/space/helpers/getLiveSpaceData.ts
new file mode 100644
index 000000000..4417ba0c1
--- /dev/null
+++ b/packages/restapi/src/lib/space/helpers/getLiveSpaceData.ts
@@ -0,0 +1,64 @@
+import { conversationHash, history } from '../../chat';
+import { MessageType } from '../../constants';
+import { EnvOptionsType, LiveSpaceData } from '../../types';
+import { initLiveSpaceData } from '../Space';
+
+interface GetLatestMessageType extends EnvOptionsType {
+ localAddress: string;
+ spaceId: string;
+ pgpPrivateKey: string;
+}
+
+const getLiveSpaceData = async ({
+ localAddress,
+ spaceId,
+ pgpPrivateKey,
+ env,
+}: GetLatestMessageType) => {
+ const threadhash = (
+ await conversationHash({
+ account: localAddress,
+ conversationId: spaceId,
+ env,
+ })
+ ).threadHash;
+
+ let liveSpaceData = initLiveSpaceData;
+
+ // fetch the message history to retrieve the latest meta message
+ for (let i = 0; i < 10; i++) {
+ const messages = await history({
+ threadhash,
+ account: localAddress,
+ pgpPrivateKey,
+ toDecrypt: true,
+ env,
+ });
+
+ let latestMetaMessage = null;
+ for (const message of messages) {
+ if (
+ message.messageType === MessageType.META &&
+ typeof message.messageObj === 'object' &&
+ message.messageObj !== null
+ ) {
+ latestMetaMessage = message;
+ break;
+ }
+ }
+
+ if (
+ latestMetaMessage !== null &&
+ typeof latestMetaMessage.messageObj === 'object' &&
+ latestMetaMessage.messageObj !== null
+ ) {
+ // found the latest meta message
+ liveSpaceData = latestMetaMessage.messageObj?.meta?.info
+ ?.arbitrary as LiveSpaceData;
+ }
+ }
+
+ return liveSpaceData;
+};
+
+export default getLiveSpaceData;
diff --git a/packages/restapi/src/lib/space/helpers/getPlainAddress.ts b/packages/restapi/src/lib/space/helpers/getPlainAddress.ts
new file mode 100644
index 000000000..d24da128a
--- /dev/null
+++ b/packages/restapi/src/lib/space/helpers/getPlainAddress.ts
@@ -0,0 +1,5 @@
+const getPlainAddress = (prefixedAddress: string) => {
+ return prefixedAddress.replace('eip155:', '');
+};
+
+export default getPlainAddress;
diff --git a/packages/restapi/src/lib/space/helpers/getSpaceListeners.ts b/packages/restapi/src/lib/space/helpers/getSpaceListeners.ts
new file mode 100644
index 000000000..e989dd2a7
--- /dev/null
+++ b/packages/restapi/src/lib/space/helpers/getSpaceListeners.ts
@@ -0,0 +1,25 @@
+const getSpaceListeners = (
+ members: {
+ wallet: string;
+ publicKey: string;
+ isSpeaker: boolean;
+ image: string;
+ }[]
+) => {
+ const listeners: {
+ wallet: string;
+ publicKey: string;
+ isSpeaker: boolean;
+ image: string;
+ }[] = [];
+
+ members.forEach((member) => {
+ if (!member.isSpeaker) {
+ listeners.push(member);
+ }
+ });
+
+ return listeners;
+};
+
+export default getSpaceListeners;
diff --git a/packages/restapi/src/lib/space/helpers/sendLiveSpaceData.ts b/packages/restapi/src/lib/space/helpers/sendLiveSpaceData.ts
new file mode 100644
index 000000000..7ca8b99dd
--- /dev/null
+++ b/packages/restapi/src/lib/space/helpers/sendLiveSpaceData.ts
@@ -0,0 +1,41 @@
+import { send } from '../../chat';
+import { MessageType } from '../../constants';
+import { EnvOptionsType, LiveSpaceData, SignerType } from '../../types';
+import { META_ACTION } from '../../types/metaTypes';
+
+interface SendLiveSpaceData extends EnvOptionsType {
+ liveSpaceData?: LiveSpaceData;
+ action: META_ACTION;
+ spaceId: string;
+ pgpPrivateKey: string;
+ signer: SignerType;
+}
+
+const sendLiveSpaceData = async ({
+ liveSpaceData,
+ action,
+ spaceId,
+ pgpPrivateKey,
+ signer,
+ env,
+}: SendLiveSpaceData) => {
+ await send({
+ receiverAddress: spaceId,
+ pgpPrivateKey,
+ env,
+ signer,
+ messageType: MessageType.META,
+ messageObj: {
+ content: 'PUSH SPACE META MESSAGE',
+ meta: {
+ action,
+ info: {
+ affected: [],
+ arbitrary: liveSpaceData,
+ },
+ },
+ },
+ });
+};
+
+export default sendLiveSpaceData;
diff --git a/packages/restapi/src/lib/space/index.ts b/packages/restapi/src/lib/space/index.ts
index d2824b32e..e2ea49306 100644
--- a/packages/restapi/src/lib/space/index.ts
+++ b/packages/restapi/src/lib/space/index.ts
@@ -1,3 +1,5 @@
+export * from './helpers/getPlainAddress';
+
export * from './spaces';
export * from './trending';
export * from './get';
diff --git a/packages/restapi/src/lib/space/initialize.ts b/packages/restapi/src/lib/space/initialize.ts
index 85f3dc682..27dc51e5d 100644
--- a/packages/restapi/src/lib/space/initialize.ts
+++ b/packages/restapi/src/lib/space/initialize.ts
@@ -1,5 +1,7 @@
+import { ChatStatus } from '../types';
import type Space from './Space';
import { get } from './get';
+import getLiveSpaceData from './helpers/getLiveSpaceData';
export interface InitializeType {
spaceId: string;
@@ -13,5 +15,17 @@ export async function initialize(this: Space, options: InitializeType) {
env: this.env,
});
- this.setSpaceSpecificData(() => space);
+ let liveSpaceData = this.spaceSpecificData.liveSpaceData;
+
+ // if the space is active then fetch the latest meta message and update the live space data state
+ if (space.status === ChatStatus.ACTIVE) {
+ liveSpaceData = await getLiveSpaceData({
+ localAddress: this.data.local.address,
+ spaceId,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ });
+ }
+
+ this.setSpaceSpecificData(() => ({ ...space, liveSpaceData }));
}
diff --git a/packages/restapi/src/lib/space/join.ts b/packages/restapi/src/lib/space/join.ts
index 7e3342c59..8bb82c441 100644
--- a/packages/restapi/src/lib/space/join.ts
+++ b/packages/restapi/src/lib/space/join.ts
@@ -1,9 +1,9 @@
-import {
- SPACE_REQUEST_TYPE,
-} from '../payloads/constants';
+import { SPACE_REQUEST_TYPE } from '../payloads/constants';
import { ChatStatus } from '../types';
import { approve } from './approve';
import { get } from './get';
+import getIncomingIndexFromAddress from '../video/helpers/getIncomingIndexFromAddress';
+import getPlainAddress from './helpers/getPlainAddress';
import type Space from './Space';
/**
@@ -25,8 +25,9 @@ export async function join(this: Space) {
let isSpeaker = false;
let isListner = false;
+ const localAddress = getPlainAddress(this.data.local.address);
space.members.forEach((member) => {
- if (member.wallet === this.data.local.address) {
+ if (getPlainAddress(member.wallet) === localAddress) {
if (member.isSpeaker) {
isSpeaker = true;
} else {
@@ -37,17 +38,38 @@ export async function join(this: Space) {
let isSpeakerPending = false;
space.pendingMembers.forEach((pendingMember) => {
if (
- pendingMember.wallet === this.data.local.address &&
+ getPlainAddress(pendingMember.wallet) === localAddress &&
pendingMember.isSpeaker
) {
isSpeakerPending = true;
}
});
+ console.log(
+ 'ISSPEAKER',
+ isSpeaker,
+ 'isListner',
+ isListner,
+ 'isSpeakerPending',
+ isSpeakerPending
+ );
+
+ const hostAddress = getPlainAddress(space.spaceCreator);
+ const incomingIndex = getIncomingIndexFromAddress(
+ this.data.incoming,
+ hostAddress
+ );
+
+ // check if we arent already connected to the host
+ if ((isSpeaker || isSpeakerPending) && incomingIndex > -1) {
+ return Promise.resolve();
+ }
+
// acc to the found role (speaker or listner), executing req logic
// if speaker is pending then approve first or if listner is pending/not found then approve first
- if (isSpeakerPending || !isListner) {
+ if (!isSpeaker && !isListner) {
+ console.log('CALLING APPROVE');
await approve({
signer: this.signer,
pgpPrivateKey: this.pgpPrivateKey,
@@ -58,7 +80,7 @@ export async function join(this: Space) {
if (isSpeaker || isSpeakerPending) {
// Call the host and join the mesh connection
- const hostAddress = space.spaceCreator.replace('eip155:', '');
+ console.log('CALLING REQUEST');
await this.request({
senderAddress: this.data.local.address,
recipientAddress: hostAddress,
@@ -74,8 +96,12 @@ export async function join(this: Space) {
spaceId: this.spaceSpecificData.spaceId,
env: this.env,
});
+ console.log('UPDATED SPACE', updatedSpace);
// update space specific data
- this.setSpaceSpecificData(() => updatedSpace);
+ this.setSpaceSpecificData(() => ({
+ ...updatedSpace,
+ liveSpaceData: this.spaceSpecificData.liveSpaceData,
+ }));
} catch (err) {
console.error(`[Push SDK] - API - Error - API ${join.name} -: `, err);
throw Error(`[Push SDK] - API - Error - API ${join.name} -: ${err}`);
diff --git a/packages/restapi/src/lib/space/leave.ts b/packages/restapi/src/lib/space/leave.ts
index 12121a86c..abbfc4b0b 100644
--- a/packages/restapi/src/lib/space/leave.ts
+++ b/packages/restapi/src/lib/space/leave.ts
@@ -10,7 +10,7 @@ export async function leave(this: Space): Promise {
// handle the case where a listner is leaving
// disconnect with every incoming peer in the mesh connection
- this.data.incoming.forEach(({ address }) => {
+ this.data.incoming.slice(1).forEach(({ address }) => {
this.disconnect({
peerAddress: address,
details: {
diff --git a/packages/restapi/src/lib/space/onJoinListener.ts b/packages/restapi/src/lib/space/onJoinListener.ts
new file mode 100644
index 000000000..176dfdcbc
--- /dev/null
+++ b/packages/restapi/src/lib/space/onJoinListener.ts
@@ -0,0 +1,71 @@
+import { pCAIP10ToWallet } from '../helpers';
+import getLiveSpaceData from './helpers/getLiveSpaceData';
+import getSpaceListeners from './helpers/getSpaceListeners';
+import sendLiveSpaceData from './helpers/sendLiveSpaceData';
+
+import { ListenerPeer, SpaceDTO } from '../types';
+import { META_ACTION } from '../types/metaTypes';
+import type Space from './Space';
+
+export interface OnJoinListenerType {
+ receivedSpaceData: SpaceDTO;
+}
+
+export async function onJoinListener(this: Space, options: OnJoinListenerType) {
+ const { receivedSpaceData } = options || {};
+
+ if (
+ pCAIP10ToWallet(this.spaceSpecificData.spaceCreator) !==
+ this.data.local.address
+ ) {
+ return;
+ }
+
+ // check whether any new listener has joined by comparing this.spaceSpecificData and receivedLiveSpaceData
+ const fetchedLiveSpaceData = await getLiveSpaceData({
+ localAddress: this.data.local.address,
+ spaceId: this.spaceSpecificData.spaceId,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ });
+ const localListeners = fetchedLiveSpaceData.listeners;
+ const receivedListeners = getSpaceListeners(receivedSpaceData.members);
+
+ const localListenerAddresses: {
+ [key: string]: number;
+ } = {};
+ localListeners.map((listener, index) => {
+ localListenerAddresses[pCAIP10ToWallet(listener.address)] = index;
+ });
+
+ const updatedListeners: ListenerPeer[] = [];
+
+ let areListenersChanged = false;
+
+ for (const listener of receivedListeners) {
+ const index = localListenerAddresses[pCAIP10ToWallet(listener.wallet)];
+
+ if (!areListenersChanged) areListenersChanged = Boolean(!index);
+
+ updatedListeners.push(
+ index
+ ? localListeners[index]
+ : {
+ address: listener.wallet,
+ handRaised: false,
+ emojiReactions: null,
+ }
+ );
+ }
+
+ if (areListenersChanged) {
+ sendLiveSpaceData({
+ spaceId: this.spaceSpecificData.spaceId,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ signer: this.signer,
+ liveSpaceData: { ...fetchedLiveSpaceData, listeners: updatedListeners },
+ action: META_ACTION.ADD_LISTENER,
+ });
+ }
+}
diff --git a/packages/restapi/src/lib/space/onReceiveMetaMessage.ts b/packages/restapi/src/lib/space/onReceiveMetaMessage.ts
new file mode 100644
index 000000000..26b626592
--- /dev/null
+++ b/packages/restapi/src/lib/space/onReceiveMetaMessage.ts
@@ -0,0 +1,18 @@
+import { LiveSpaceData } from '../types';
+import type Space from './Space';
+
+export interface OnReceiveMetaMessageType {
+ receivedLiveSpaceData: LiveSpaceData;
+}
+
+export async function onReceiveMetaMessage(
+ this: Space,
+ options: OnReceiveMetaMessageType
+) {
+ const { receivedLiveSpaceData } = options || {};
+
+ this.setSpaceSpecificData(() => ({
+ ...this.spaceSpecificData,
+ liveSpaceData: receivedLiveSpaceData,
+ }));
+}
diff --git a/packages/restapi/src/lib/space/rejectPromotionRequest.ts b/packages/restapi/src/lib/space/rejectPromotionRequest.ts
index b4eddee56..abc5cc7bf 100644
--- a/packages/restapi/src/lib/space/rejectPromotionRequest.ts
+++ b/packages/restapi/src/lib/space/rejectPromotionRequest.ts
@@ -1,4 +1,8 @@
+import { produce } from 'immer';
import type Space from './Space';
+import getLiveSpaceData from './helpers/getLiveSpaceData';
+import sendLiveSpaceData from './helpers/sendLiveSpaceData';
+import { META_ACTION } from '../types/metaTypes';
export interface RejectPromotionRequestType {
promoteeAddress: string;
@@ -14,4 +18,28 @@ export async function rejectPromotionRequest(
this.disconnect({
peerAddress: promoteeAddress,
});
+
+ // update live space info
+ const oldLiveSpaceData = await getLiveSpaceData({
+ localAddress: this.data.local.address,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ spaceId: this.spaceSpecificData.spaceId,
+ });
+ const updatedLiveSpaceData = produce(oldLiveSpaceData, (draft) => {
+ const listnerIndex = draft.listeners.findIndex(listner => listner.address === promoteeAddress);
+ draft.listeners[listnerIndex].handRaised = false;
+ });
+ await sendLiveSpaceData({
+ liveSpaceData: updatedLiveSpaceData,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ spaceId: this.spaceSpecificData.spaceId,
+ signer: this.signer,
+ action: META_ACTION.USER_INTERACTION, // TODO: Add a reject request type
+ });
+ this.setSpaceSpecificData(() => ({
+ ...this.spaceSpecificData,
+ liveSpaceData: updatedLiveSpaceData,
+ }));
}
diff --git a/packages/restapi/src/lib/space/removeSpeaker.ts b/packages/restapi/src/lib/space/removeSpeaker.ts
deleted file mode 100644
index 84c214d02..000000000
--- a/packages/restapi/src/lib/space/removeSpeaker.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { EnvOptionsType } from '../types';
-import { groupDtoToSpaceDto } from '../chat/helpers';
-import {
- removeAdmins
-} from '../chat/removeAdmins';
-import type Space from './Space';
-
-export interface RemoveSpeakerType extends EnvOptionsType {
- address: string;
-}
-
-export async function removeSpeaker(
- this: Space,
- options: RemoveSpeakerType
-): Promise {
- const { address } = options;
- try {
- const group = await removeAdmins({
- chatId: this.spaceSpecificData.spaceId,
- admins: [address],
- signer: this.signer,
- env: this.env,
- pgpPrivateKey: this.pgpPrivateKey,
- });
-
- // update space specific data
- this.setSpaceSpecificData(() => groupDtoToSpaceDto(group));
- } catch (err) {
- console.error(
- `[Push SDK] - API - Error - API ${removeSpeaker.name} -: `,
- err
- );
- throw Error(
- `[Push SDK] - API - Error - API ${removeSpeaker.name} -: ${err}`
- );
- }
-}
diff --git a/packages/restapi/src/lib/space/requestToBePromoted.ts b/packages/restapi/src/lib/space/requestToBePromoted.ts
index b52992841..80b9c7d13 100644
--- a/packages/restapi/src/lib/space/requestToBePromoted.ts
+++ b/packages/restapi/src/lib/space/requestToBePromoted.ts
@@ -3,7 +3,6 @@ import type Space from './Space';
export interface RequestToBePromotedType {
role: SPACE_INVITE_ROLES;
- spaceId: string;
promotorAddress: string;
}
@@ -11,13 +10,13 @@ export async function requestToBePromoted(
this: Space,
options: RequestToBePromotedType
) {
- const { role, spaceId, promotorAddress } = options || {};
+ const { role, promotorAddress } = options || {};
// requesting host to include local computer into the mesh connection
this.request({
senderAddress: this.data.local.address,
recipientAddress: promotorAddress,
- chatId: spaceId,
+ chatId: this.spaceSpecificData.spaceId,
details: {
type: SPACE_REQUEST_TYPE.REQUEST_TO_PROMOTE,
data: {
diff --git a/packages/restapi/src/lib/space/start.ts b/packages/restapi/src/lib/space/start.ts
index f15f28449..79a641030 100644
--- a/packages/restapi/src/lib/space/start.ts
+++ b/packages/restapi/src/lib/space/start.ts
@@ -1,4 +1,9 @@
-import { EnvOptionsType, SignerType, ChatStatus } from '../types';
+import {
+ EnvOptionsType,
+ SignerType,
+ ChatStatus,
+ LiveSpaceData,
+} from '../types';
import {
groupDtoToSpaceDto,
getSpacesMembersList,
@@ -19,6 +24,9 @@ export interface StartSpaceType extends EnvOptionsType {
import type Space from './Space';
import { produce } from 'immer';
+import { pCAIP10ToWallet } from '../helpers';
+import { META_ACTION } from '../types/metaTypes';
+import sendLiveSpaceData from './helpers/sendLiveSpaceData';
type StartType = {
livepeerApiKey: string;
@@ -28,8 +36,6 @@ export async function start(this: Space, options: StartType): Promise {
const { livepeerApiKey } = options || {};
try {
- // TODO: Only allow the host to execute this function
-
// host should have there audio stream
if (!this.data.local.stream) {
throw new Error('Local audio stream not found');
@@ -46,6 +52,11 @@ export async function start(this: Space, options: StartType): Promise {
);
}
+ // Only host is allowed to start a space
+ if (this.data.local.address !== pCAIP10ToWallet(space.spaceCreator)) {
+ throw new Error('Only host is allowed to start a space');
+ }
+
const convertedMembers = getSpacesMembersList(
space.members,
space.pendingMembers
@@ -70,11 +81,32 @@ export async function start(this: Space, options: StartType): Promise {
status: ChatStatus.ACTIVE,
});
+ const liveSpaceData: LiveSpaceData = {
+ host: {
+ address: this.data.local.address,
+ audio: this.data.local.audio,
+ emojiReactions: null,
+ },
+ coHosts: [],
+ speakers: [],
+ listeners: [],
+ };
+
+ await sendLiveSpaceData({
+ liveSpaceData,
+ action: META_ACTION.CREATE_SPACE,
+ spaceId: this.spaceSpecificData.spaceId,
+ signer: this.signer,
+ pgpPrivateKey: this.pgpPrivateKey,
+ env: this.env,
+ });
+
// update space data
this.setSpaceData((oldSpaceData) => {
return produce(oldSpaceData, (draft) => {
draft = {
...groupDtoToSpaceDto(group),
+ liveSpaceData,
connectionData: draft.connectionData,
};
draft.connectionData.meta.broadcast = {
diff --git a/packages/restapi/src/lib/space/stop.ts b/packages/restapi/src/lib/space/stop.ts
index 4f69914ec..9a3e82114 100644
--- a/packages/restapi/src/lib/space/stop.ts
+++ b/packages/restapi/src/lib/space/stop.ts
@@ -48,7 +48,10 @@ export async function stop(this: Space): Promise {
});
// update space specific data
- this.setSpaceSpecificData(() => groupDtoToSpaceDto(group));
+ this.setSpaceSpecificData(() => ({
+ ...groupDtoToSpaceDto(group),
+ liveSpaceData: this.spaceSpecificData.liveSpaceData,
+ }));
// stop livepeer playback
@@ -56,7 +59,7 @@ export async function stop(this: Space): Promise {
- disconnect with every incoming peer in the mesh connection
- other peers should also end their connections as we want to destroy the mesh connection
*/
- this.data.incoming.forEach(({ address }) => {
+ this.data.incoming.slice(1).forEach(({ address }) => {
this.disconnect({
peerAddress: address,
details: {
diff --git a/packages/restapi/src/lib/space/update.ts b/packages/restapi/src/lib/space/update.ts
index 266baf456..2ccbea8ef 100644
--- a/packages/restapi/src/lib/space/update.ts
+++ b/packages/restapi/src/lib/space/update.ts
@@ -63,7 +63,10 @@ export async function update(
});
// update space specific data
- this.setSpaceSpecificData(() => groupDtoToSpaceDto(group));
+ this.setSpaceSpecificData(() => ({
+ ...groupDtoToSpaceDto(group),
+ liveSpaceData: this.spaceSpecificData.liveSpaceData,
+ }));
} catch (err) {
console.error(`[Push SDK] - API - Error - API ${update.name} -: `, err);
throw Error(`[Push SDK] - API - Error - API ${update.name} -: ${err}`);
diff --git a/packages/restapi/src/lib/types/index.ts b/packages/restapi/src/lib/types/index.ts
index a3b440803..e99f6d158 100644
--- a/packages/restapi/src/lib/types/index.ts
+++ b/packages/restapi/src/lib/types/index.ts
@@ -306,7 +306,7 @@ export interface Member {
export enum ChatStatus {
ACTIVE = 'ACTIVE',
PENDING = 'PENDING',
- ENDED = 'ENDED'
+ ENDED = 'ENDED',
}
export interface GroupDTO {
members: {
@@ -368,7 +368,34 @@ export interface SpaceDTO {
inviteeDetails?: { [key: string]: SPACE_INVITE_ROLES };
}
-export interface SpaceData extends SpaceDTO {
+export interface Peer {
+ address: string;
+ emojiReactions: {
+ emoji: string;
+ expiresIn: string;
+ } | null;
+}
+
+export interface ListenerPeer extends Peer {
+ handRaised: boolean;
+}
+
+export interface AdminPeer extends Peer {
+ audio: boolean | null;
+}
+
+export interface LiveSpaceData {
+ host: AdminPeer | null;
+ coHosts: AdminPeer[];
+ speakers: AdminPeer[];
+ listeners: ListenerPeer[];
+}
+
+export interface SpaceSpecificData extends SpaceDTO {
+ liveSpaceData: LiveSpaceData;
+}
+
+export interface SpaceData extends SpaceSpecificData {
connectionData: VideoCallData;
}
diff --git a/packages/restapi/src/lib/types/metaTypes.ts b/packages/restapi/src/lib/types/metaTypes.ts
index e87c1ee7b..a5fc4ddf9 100644
--- a/packages/restapi/src/lib/types/metaTypes.ts
+++ b/packages/restapi/src/lib/types/metaTypes.ts
@@ -2,7 +2,7 @@
* This file defines the type for meta property for a Push Chat message
*/
-const enum META_ACTION {
+export const enum META_ACTION {
/**
* DEFAULT GROUP ACTIONS
*/
diff --git a/packages/restapi/src/lib/video/Video.ts b/packages/restapi/src/lib/video/Video.ts
index f1d340979..df7618e72 100644
--- a/packages/restapi/src/lib/video/Video.ts
+++ b/packages/restapi/src/lib/video/Video.ts
@@ -55,6 +55,7 @@ export const initVideoCallData: VideoCallData = {
video: null,
address: '',
},
+ // TODO: Remove the default element in incoming array
incoming: [
{
stream: null,
@@ -74,7 +75,7 @@ export class Video {
protected pgpPrivateKey: string;
protected env: ENV;
protected callType: VIDEO_CALL_TYPE;
- protected onReceiveStream: (receivedStream: MediaStream) => void;
+ protected onReceiveStream: (receivedStream: MediaStream, senderAddress: string, audio:boolean | null) => Promise;
// storing the peer instance
private peerInstances: {
@@ -91,8 +92,8 @@ export class Video {
env = Constants.ENV.PROD,
setData,
callType = VIDEO_CALL_TYPE.PUSH_VIDEO,
- onReceiveStream = () => {
- return;
+ onReceiveStream = async () => {
+ return Promise.resolve();
},
}: {
signer: SignerType;
@@ -101,7 +102,7 @@ export class Video {
setData: (fn: (data: VideoCallData) => VideoCallData) => void;
env?: ENV;
callType?: VIDEO_CALL_TYPE;
- onReceiveStream?: (receivedStream: MediaStream) => void;
+ onReceiveStream?: (receivedStream: MediaStream, senderAddress: string, audio:boolean | null) => Promise;
}) {
this.signer = signer;
this.chainId = chainId;
@@ -257,14 +258,33 @@ export class Video {
value: this.data.local.audio,
})
);
+ // send the addresses the local peer is connected to remote peer
+ const connectedAddresses = getConnectedAddresses({
+ incomingPeers: this.data.incoming,
+ });
+ console.log(
+ 'REQUEST - SENDING THE CONNECTED ADDRESSES',
+ 'connectedAddresses',
+ connectedAddresses
+ );
+ this.peerInstances[recipientAddress].send(
+ JSON.stringify({
+ type: 'connectedAddresses',
+ value: connectedAddresses,
+ })
+ );
});
this.peerInstances[recipientAddress].on('data', (data: any) => {
if (isJSON(data)) {
const parsedData = JSON.parse(data);
- if (parsedData.type === 'connectedAddress') {
- console.log('CONNECTED ADDRESSES', parsedData.value);
+ if (parsedData.type === 'connectedAddresses') {
+ console.log(
+ 'REQUEST - RECEIVING CONNECTED ADDRESSES',
+ 'CONNECTED ADDRESSES',
+ parsedData.value
+ );
const receivedConnectedAddresses = parsedData.value;
const localConnectedAddresses = getConnectedAddresses({
@@ -278,17 +298,15 @@ export class Video {
localConnectedAddresses,
receivedConnectedAddresses,
});
- for (const connectToAddress of connectToAddresses) {
- this.request({
- senderAddress,
- recipientAddress: connectToAddress,
- chatId,
- details: {
- type: SPACE_REQUEST_TYPE.ESTABLISH_MESH,
- data: {},
- },
- });
- }
+ this.request({
+ senderAddress,
+ recipientAddress: connectToAddresses,
+ chatId,
+ details: {
+ type: SPACE_REQUEST_TYPE.ESTABLISH_MESH,
+ data: {},
+ },
+ });
}
if (parsedData.type === 'isVideoOn') {
@@ -371,13 +389,13 @@ export class Video {
'stream',
(currentStream: MediaStream) => {
console.log('received incoming stream', currentStream);
- this.onReceiveStream(currentStream);
+ const incomingIndex = getIncomingIndexFromAddress(
+ this.data.incoming,
+ recipientAddress
+ );
+ this.onReceiveStream(currentStream, recipientAddress, this.data.incoming[incomingIndex].audio)
this.setData((oldData) => {
return produce(oldData, (draft) => {
- const incomingIndex = getIncomingIndexFromAddress(
- oldData.incoming,
- recipientAddress
- );
draft.incoming[incomingIndex].stream = currentStream;
});
});
@@ -478,6 +496,7 @@ export class Video {
status: VideoCallStatus.RETRY_INITIALIZED,
chatId,
signalData: null,
+ callType: this.callType,
env: this.env,
}
);
@@ -527,6 +546,22 @@ export class Video {
})
);
+ // send the addresses the local peer is connected to remote peer
+ const connectedAddresses = getConnectedAddresses({
+ incomingPeers: this.data.incoming,
+ });
+ console.log(
+ 'ACCEPT REQUEST - SENDING THE CONNECTED ADDRESSES',
+ 'connectedAddresses',
+ connectedAddresses
+ );
+ this.peerInstances[recipientAddress].send(
+ JSON.stringify({
+ type: 'connectedAddresses',
+ value: connectedAddresses,
+ })
+ );
+
// set videoCallInfo state with status connected for the receiver's end
this.setData((oldData) => {
return produce(oldData, (draft) => {
@@ -543,8 +578,12 @@ export class Video {
if (isJSON(data)) {
const parsedData = JSON.parse(data);
- if (parsedData.type === 'connectedAddress') {
- console.log('CONNECTED ADDRESSES', parsedData.value);
+ if (parsedData.type === 'connectedAddresses') {
+ console.log(
+ 'ACCEPT REQUEST - RECEIVING CONNECTED ADDRESSES',
+ 'CONNECTED ADDRESSES',
+ parsedData.value
+ );
const receivedConnectedAddresses = parsedData.value;
const localConnectedAddresses = getConnectedAddresses({
@@ -558,25 +597,15 @@ export class Video {
localConnectedAddresses,
receivedConnectedAddresses,
});
- for (const connectToAddress of connectToAddresses) {
- this.request({
- senderAddress,
- recipientAddress: connectToAddress,
- chatId,
- details: {
- type: SPACE_REQUEST_TYPE.ESTABLISH_MESH,
- data: {},
- },
- });
- }
-
- // send the addresses the local peer is connected to remote peer
- this.peerInstances[recipientAddress].send(
- JSON.stringify({
- type: 'connectedAddresses',
- value: localConnectedAddresses,
- })
- );
+ this.request({
+ senderAddress,
+ recipientAddress: connectToAddresses,
+ chatId,
+ details: {
+ type: SPACE_REQUEST_TYPE.ESTABLISH_MESH,
+ data: {},
+ },
+ });
}
if (parsedData.type === 'isVideoOn') {
@@ -659,13 +688,13 @@ export class Video {
'stream',
(currentStream: MediaStream) => {
console.log('received incoming stream', currentStream);
- this.onReceiveStream(currentStream);
+ const incomingIndex = getIncomingIndexFromAddress(
+ this.data.incoming,
+ recipientAddress
+ );
+ this.onReceiveStream(currentStream, recipientAddress, this.data.incoming[incomingIndex].audio);
this.setData((oldData) => {
return produce(oldData, (draft) => {
- const incomingIndex = getIncomingIndexFromAddress(
- oldData.incoming,
- recipientAddress
- );
draft.incoming[incomingIndex].stream = currentStream;
});
});
@@ -707,17 +736,6 @@ export class Video {
this.peerInstances[peerAddress]?.signal(signalData);
- // send the addresses the local peer is connected to remote peer
- const connectedAddresses = getConnectedAddresses({
- incomingPeers: this.data.incoming,
- });
- this.peerInstances[peerAddress].send(
- JSON.stringify({
- type: 'connectedAddresses',
- value: connectedAddresses,
- })
- );
-
// set videoCallInfo state with status connected for the caller's end
this.setData((oldData) => {
return produce(oldData, (draft) => {
@@ -737,6 +755,8 @@ export class Video {
const { peerAddress, details } = options || {};
try {
+ console.log("DISCONNECT OPTIONS", options);
+
const incomingIndex = getIncomingIndexFromAddress(
this.data.incoming,
peerAddress
@@ -800,20 +820,16 @@ export class Video {
if (this.data.local.video !== state) {
// need to change the video state
- const incomingIndex = getIncomingIndexFromAddress(
- this.data.incoming,
- peerAddress
- );
-
- if (
- this.data.incoming[incomingIndex].status === VideoCallStatus.CONNECTED
- ) {
- this.peerInstances[peerAddress]?.send(
- JSON.stringify({
- type: 'isVideoOn',
- value: state,
- })
- );
+ // signal all the connected peers that the local peer has changed their video state
+ for (const incomingPeer of this.data.incoming) {
+ if (incomingPeer.status === VideoCallStatus.CONNECTED) {
+ this.peerInstances[incomingPeer.address]?.send(
+ JSON.stringify({
+ type: 'isVideoOn',
+ value: state,
+ })
+ );
+ }
}
if (this.data.local.stream) {
if (state) {
@@ -836,17 +852,13 @@ export class Video {
if (this.data.local.audio !== state) {
// need to change the audio state
- const incomingIndex = getIncomingIndexFromAddress(
- this.data.incoming,
- peerAddress
- );
-
- if (
- this.data.incoming[incomingIndex].status === VideoCallStatus.CONNECTED
- ) {
- this.peerInstances[peerAddress]?.send(
- JSON.stringify({ type: 'isAudioOn', value: state })
- );
+ // signal all the connected peers that the local peer has changed their audio state
+ for (const incomingPeer of this.data.incoming) {
+ if (incomingPeer.status === VideoCallStatus.CONNECTED) {
+ this.peerInstances[incomingPeer.address]?.send(
+ JSON.stringify({ type: 'isAudioOn', value: state })
+ );
+ }
}
if (this.data.local.stream) {
if (state) {
diff --git a/packages/restapi/src/lib/video/helpers/getConnectedAddresses.ts b/packages/restapi/src/lib/video/helpers/getConnectedAddresses.ts
index 7e9d9a149..89671145d 100644
--- a/packages/restapi/src/lib/video/helpers/getConnectedAddresses.ts
+++ b/packages/restapi/src/lib/video/helpers/getConnectedAddresses.ts
@@ -1,3 +1,4 @@
+import getPlainAddress from '../../space/helpers/getPlainAddress';
import { PeerData, VideoCallStatus } from '../../types';
const getConnectedAddresses = ({
@@ -8,7 +9,7 @@ const getConnectedAddresses = ({
const connectedAddresses: string[] = [];
incomingPeers.forEach((incomingPeer) => {
if (incomingPeer.status === VideoCallStatus.CONNECTED) {
- connectedAddresses.push(incomingPeer.address);
+ connectedAddresses.push(getPlainAddress(incomingPeer.address));
}
});
return connectedAddresses;
diff --git a/packages/restapi/src/lib/video/helpers/sendVideoCallNotification.ts b/packages/restapi/src/lib/video/helpers/sendVideoCallNotification.ts
index 935375d6e..ab4b2664e 100644
--- a/packages/restapi/src/lib/video/helpers/sendVideoCallNotification.ts
+++ b/packages/restapi/src/lib/video/helpers/sendVideoCallNotification.ts
@@ -93,8 +93,7 @@ const sendVideoCallNotification = async (
cta: '',
img: '',
additionalMeta: {
- // type: `${callType}+1`,
- type: `${VIDEO_CALL_TYPE.PUSH_VIDEO}+1`,
+ type: `${callType}+1`,
data: JSON.stringify(videoData),
},
},
diff --git a/packages/uiweb/CHANGELOG.md b/packages/uiweb/CHANGELOG.md
index 032942928..182d1e341 100644
--- a/packages/uiweb/CHANGELOG.md
+++ b/packages/uiweb/CHANGELOG.md
@@ -2,6 +2,29 @@
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
+## [1.1.4](https://github.com/ethereum-push-notification-service/push-sdk/compare/uiweb-1.1.3...uiweb-1.1.4) (2023-07-20)
+
+
+### Bug Fixes
+
+* merge main ([24784e9](https://github.com/ethereum-push-notification-service/push-sdk/commit/24784e9ceca8f3757481f3be72efd0ca1ff3fba8))
+
+
+
+## [1.1.3](https://github.com/ethereum-push-notification-service/push-sdk/compare/uiweb-1.1.2...uiweb-1.1.3) (2023-07-20)
+
+
+### Bug Fixes
+
+* fixed bugs ([#566](https://github.com/ethereum-push-notification-service/push-sdk/issues/566)) ([481d8fc](https://github.com/ethereum-push-notification-service/push-sdk/commit/481d8fcd7c40325654ba490640daabc38ee2f96e))
+* Merge branch 'main' into deployment ([9f77f39](https://github.com/ethereum-push-notification-service/push-sdk/commit/9f77f391b26111006891c10a3cc8eab06e26f14f))
+
+
+
+## [1.1.2](https://github.com/ethereum-push-notification-service/push-sdk/compare/uiweb-1.1.1...uiweb-1.1.2) (2023-07-18)
+
+
+
## [1.1.1](https://github.com/ethereum-push-notification-service/push-sdk/compare/uiweb-1.1.0...uiweb-1.1.1) (2023-07-17)
diff --git a/packages/uiweb/package.json b/packages/uiweb/package.json
index f61be7256..b8a2a0e2a 100644
--- a/packages/uiweb/package.json
+++ b/packages/uiweb/package.json
@@ -1,6 +1,6 @@
{
"name": "@pushprotocol/uiweb",
- "version": "1.1.1",
+ "version": "1.1.4",
"publishConfig": {
"registry": "https://registry.npmjs.org/"
},
@@ -13,7 +13,7 @@
"html-react-parser": "^1.4.13",
"gif-picker-react": "^1.1.0",
"font-awesome": "^4.7.0",
- "moment":"^2.29.4"
+ "moment": "^2.29.4"
},
"peerDependencies": {
"@pushprotocol/restapi": "^1.2.15",
diff --git a/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotification.tsx b/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotification.tsx
index 1af763bba..535924540 100644
--- a/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotification.tsx
+++ b/packages/uiweb/src/lib/components/chatAndNotification/ChatAndNotification.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect, useState, useContext } from 'react';
+import React, { useEffect, useState, useContext, useRef } from 'react';
import styled from 'styled-components';
import { MinimisedModalHeader } from './MinimisedModalHeader';
@@ -45,9 +45,11 @@ export const ChatAndNotification = () => {
requestsFeed,
chatsFeed,
selectedChatId,
+ setFinishedFetchingChats,
+ setFinishedFetchingRequests,
setChats
} = useContext(ChatMainStateContext);
- const { setInboxNotifsFeed, setSpamNotifsFeed } = useContext(
+ const { setInboxNotifsFeed, setSpamNotifsFeed,setFinishedFetchingInbox,setFinishedFetchingSpam } = useContext(
NotificationMainStateContext
);
const {
@@ -63,6 +65,7 @@ export const ChatAndNotification = () => {
const { fetchRequests } = useFetchRequests();
const { fetchChats } = useFetchChats();
const { fetchChat } = useFetchChat();
+ const modalRef = useRef(null);
const { fetchUserSubscriptions } = useFetchUserSubscriptions();
useChatNotificationSocket({});
@@ -73,6 +76,10 @@ export const ChatAndNotification = () => {
setRequestsFeed({});
setInboxNotifsFeed({});
setSpamNotifsFeed({});
+ setFinishedFetchingInbox(false);
+ setFinishedFetchingSpam(false);
+ setFinishedFetchingChats(false);
+ setFinishedFetchingRequests(false);
// set active tab if present
if (activeChosenTab) {
setActiveTab(activeChosenTab);
@@ -157,7 +164,7 @@ export const ChatAndNotification = () => {
selectedChat = getDefaultFeedObject({ user: result });
}
}
-
+
}
setSearchedChats({
[selectedChat.did.toLowerCase() ?? selectedChat.chatId]: selectedChat,
@@ -182,13 +189,31 @@ export const ChatAndNotification = () => {
setModalOpen(!modalOpen);
};
- const toggleOverflow = (val: string) => {
- if (typeof window != 'undefined' && window.document) {
- document.body.style.overflowY = val;
- }
- };
-
+
+ useEffect(() => {
+ const modalElement = modalRef.current;
+ if (!modalElement) return;
+
+ const handleScroll = (event: WheelEvent) => {
+ const { scrollTop, scrollHeight, clientHeight } = modalElement;
+ const isScrolledToBottom = scrollTop + clientHeight >= scrollHeight;
+
+ // If scrolled to the bottom of the modal, prevent further scrolling
+ if (isScrolledToBottom && event.deltaY > 0) {
+ // event.preventDefault();
+ event.stopPropagation();
+ }
+ };
+
+ modalElement.addEventListener('wheel', handleScroll);
+
+ // Cleanup the event listener when the component unmounts
+ return () => {
+ modalElement.removeEventListener('wheel', handleScroll);
+ };
+ }, []);
+
return (
{
background="#fff"
right="12px"
bottom="18px"
+ className='modal'
overflow="hidden"
-
+ ref={modalRef}
+
// onMouseEnter={() => toggleOverflow('hidden')}
// onMouseLeave={() => toggleOverflow('auto')}
>
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
index 4b13966ce..68e1679cc 100644
--- a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatsFeedList.tsx
+++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/ChatsFeedList.tsx
@@ -17,7 +17,7 @@ import { SidebarPlaceholder } from '../SidebarPlaceholder';
import type { ChatMainStateContextType } from '../../../../../context/chatAndNotification/chat/chatMainStateContext';
export const ChatsFeedList = () => {
- const { chatsFeed, setChatsFeed } =
+ const { chatsFeed, setChatsFeed,finishedFetchingChats,setFinishedFetchingChats } =
useContext(ChatMainStateContext);
const pageRef = useRef(null);
const [page, setPage] = useState(1);
@@ -46,7 +46,7 @@ export const ChatsFeedList = () => {
useEffect(() => {
if (
!isInViewport1 ||
- loading
+ loading || finishedFetchingChats
// ||
// Object.keys(chatsFeed).length < chatLimit
) {
@@ -66,6 +66,7 @@ export const ChatsFeedList = () => {
try {
setPaginateLoading(true);
const feeds = await fetchChats({ page, chatLimit });
+ if(!Object.keys(feeds || {}).length) setFinishedFetchingChats(true);
const newFeed: ChatFeedsType = { ...chatsFeed, ...feeds };
setChatsFeed(newFeed);
} catch (error) {
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
index 4b8481ac1..f337fdde2 100644
--- a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/RequestsFeedList.tsx
+++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/chatSidebar/RequestsFeedList.tsx
@@ -11,7 +11,7 @@ import { useIsInViewport } from '../../../../../hooks';
import type { ChatMainStateContextType } from '../../../../../context/chatAndNotification/chat/chatMainStateContext';
export const RequestsFeedList = () => {
- const { requestsFeed, setRequestsFeed } = useContext(ChatMainStateContext);
+ const { requestsFeed, setRequestsFeed,finishedFetchingRequests,setFinishedFetchingRequests } = useContext(ChatMainStateContext);
const pageRef = useRef(null);
const [page, setPage] = useState(1);
const [paginateLoading, setPaginateLoading] = useState(false);
@@ -38,7 +38,7 @@ export const RequestsFeedList = () => {
useEffect(() => {
if (
!isInViewport1 ||
- loading
+ loading || finishedFetchingRequests
// ||
// Object.keys(requestsFeed).length < requestLimit
) {
@@ -58,6 +58,7 @@ export const RequestsFeedList = () => {
try {
setPaginateLoading(true);
const feeds = await fetchRequests({ page, requestLimit });
+ if(!Object.keys(feeds || {}).length) setFinishedFetchingRequests(true);
const newFeed: ChatFeedsType = { ...requestsFeed, ...feeds };
setRequestsFeed(newFeed);
} catch (error) {
@@ -75,7 +76,7 @@ export const RequestsFeedList = () => {
justifyContent="start"
width='100%'
flexDirection="column"
-
+
>
{(!loading || paginateLoading) && Object.keys(requestsFeed || {}).length ? (
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
index be5f08311..7a24fc805 100644
--- a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/InboxNotificationFeedList.tsx
+++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/InboxNotificationFeedList.tsx
@@ -28,6 +28,8 @@ export const InboxNotificationFeedList = () => {
setAllInboxNotifsFeed,
setSpamNotifsFeed,
spamNotifsFeed,
+ finishedFetchingInbox,
+ setFinishedFetchingInbox,
} = useContext(NotificationMainStateContext);
const pageRef = useRef(null);
const { account, env } = useContext(ChatAndNotificationPropsContext);
@@ -36,7 +38,7 @@ export const InboxNotificationFeedList = () => {
const isInViewport1 = useIsInViewport(pageRef, '1px');
const { fetchNotification, loading } = useFetchNotification();
-
+
const fetchSpamNotificationList = async () => {
const feeds: NotificationFeedsType | undefined = await fetchNotification({
page: 1,
@@ -90,10 +92,10 @@ export const InboxNotificationFeedList = () => {
}, [fetchNotification, env, page, account]);
useEffect(() => {
-
+
if (
!isInViewport1 ||
- loading
+ loading || finishedFetchingInbox
||
Object.keys(inboxNotifsFeed).length < notificationLimit
) {
@@ -112,9 +114,10 @@ export const InboxNotificationFeedList = () => {
}
try {
setPaginateLoading(true);
- const feeds = await fetchNotification({ page, limit: notificationLimit });
+ const feeds = await fetchNotification({ page, limit: notificationLimit });
+ if(!Object.keys(feeds || {}).length) setFinishedFetchingInbox(true);
const newFeed:NotificationFeedsType = {...inboxNotifsFeed,...feeds};
-
+
setInboxNotifsFeed(newFeed);
} catch (error) {
console.log(error);
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
index 8c2543c42..de6c554fa 100644
--- a/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/SpamNotificationFeedList.tsx
+++ b/packages/uiweb/src/lib/components/chatAndNotification/modal/sidebar/notificationSidebar/SpamNotificationFeedList.tsx
@@ -16,7 +16,7 @@ import type { NotificationFeedsType } from '../../../../../types';
import useFetchNotification from '../../../../../hooks/notifications/useFetchNotification';
export const SpamNotificationFeedList = () => {
- const { spamNotifsFeed, setSpamNotifsFeed } = useContext(
+ const { spamNotifsFeed, setSpamNotifsFeed,finishedFetchingSpam,setFinishedFetchingSpam } = useContext(
NotificationMainStateContext
);
const pageRef = useRef(null);
@@ -48,7 +48,7 @@ export const SpamNotificationFeedList = () => {
useEffect(() => {
if (
!isInViewport1 ||
- loading ||
+ loading || finishedFetchingSpam||
Object.keys(spamNotifsFeed).length < notificationLimit
) {
return;
@@ -72,8 +72,9 @@ export const SpamNotificationFeedList = () => {
limit: notificationLimit,
spam: true,
});
+ if(!Object.keys(feeds || {}).length) setFinishedFetchingSpam(true);
const newFeed: NotificationFeedsType = { ...spamNotifsFeed, ...feeds };
-
+
setSpamNotifsFeed(newFeed);
} catch (error) {
@@ -90,7 +91,7 @@ export const SpamNotificationFeedList = () => {
justifyContent="start"
flexDirection="column"
width="100%"
-
+
padding="0 3px"
>
{(!loading || paginateLoading) &&
diff --git a/packages/uiweb/src/lib/components/space/SpaceBanner/SpaceBanner.tsx b/packages/uiweb/src/lib/components/space/SpaceBanner/SpaceBanner.tsx
index 7bc1f19ff..9dd2c647a 100644
--- a/packages/uiweb/src/lib/components/space/SpaceBanner/SpaceBanner.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceBanner/SpaceBanner.tsx
@@ -1,5 +1,5 @@
-import React from 'react';
-import styled from 'styled-components';
+import React, { useEffect } from 'react';
+import styled, { ThemeProvider } from 'styled-components';
import { SpaceBannerLoadingSkeleton } from './SpaceBannerLoadingSkeleton';
@@ -11,15 +11,19 @@ import { ParticipantContainer } from '../reusables/ParticipantContainer';
import { HostPfpContainer } from '../reusables';
import live from './../../../icons/live.svg';
-import scheduled from './../../../icons/scheduled.svg';
-import { useGetSpaceInfo } from './../../../hooks';
+import { Scheduled } from '../../../icons/scheduled';
+import {
+ useGetSpaceInfo,
+ usePushSpaceSocket,
+ useSpaceData,
+} from './../../../hooks';
export interface ISpaceBannerProps {
spaceId: string;
orientation?: 'maximized' | 'minimized' | 'pill';
isInvite?: boolean;
onBannerClick?: (arg: string) => void;
- onJoin?: any;
+ actionCallback?: any;
}
/**
@@ -38,11 +42,22 @@ export const SpaceBanner: React.FC = ({
orientation,
isInvite,
onBannerClick,
- onJoin,
+ actionCallback,
}) => {
const theme = React.useContext(ThemeContext);
const spaceData = useGetSpaceInfo(spaceId);
+ const {
+ spacesObjectRef,
+ spaceObjectData,
+ initSpaceObject,
+ setSpaceWidgetId,
+ isSpeaker,
+ isListener,
+ account,
+ env,
+ } = useSpaceData();
+
const spaceStatus = getSpaceStatus(spaceData?.status);
const handleClick = () => {
@@ -51,77 +66,76 @@ export const SpaceBanner: React.FC = ({
}
};
+ const handleJoinSpace = async () => {
+ await initSpaceObject(spaceData?.spaceId as string);
+ actionCallback();
+ setSpaceWidgetId(spaceData?.spaceId as string);
+ };
+
+ usePushSpaceSocket({ account, env });
+
// Check if the spaceData is not available, show the skeleton loading effect
if (!spaceData) {
return ;
}
return (
-
- {orientation === 'maximized' && (
-
- )}
- {orientation === 'maximized' ? null : (
-
- )}
-
- {orientation === 'pill'
- ? `${spaceData?.spaceName.slice(0, 20)}...`
- : spaceData?.spaceName}
-
-
-
-
-
- {isInvite === true && spaceStatus === 'Live' ? (
- Join this space
- ) : isInvite === true &&
- spaceStatus === 'Scheduled' ? (
- Remind Me
- ) : null}
-
+
+ {isInvite === true && spaceStatus === 'Live' ? (
+
+ Join this space
+
+ ) : isInvite === true && spaceStatus === 'Scheduled' ? (
+ Remind Me
+ ) : null}
+
+
);
};
@@ -163,14 +177,17 @@ const Container = styled.div`
: props.orientation === 'minimized'
? '12px'
: '24px'};
- color: ${(props) => (props.status === 'Live' ? '#f5f5f5' : '#1E1E1E')};
+ color: ${(props) =>
+ props.status === 'Live'
+ ? `${props.theme.titleTextColor}`
+ : `${props.theme.textColorPrimary}`};
min-width: 0;
text-overflow: ellipsis;
overflow: hidden;
- cursor: ${props => props.clickable && 'pointer'};
+ cursor: ${(props) => props.clickable && 'pointer'};
`;
-const Title = styled.div<{ orientation?: string }>`
+const Title = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-start;
@@ -185,6 +202,10 @@ const Title = styled.div<{ orientation?: string }>`
? '16px'
: '12px'};
line-height: 130%;
+ color: ${(props) =>
+ props.status === 'Live'
+ ? props.theme.titleTextColor
+ : props.theme.textColorPrimary};
width: 90%;
line-clamp: ${(props) => (props.orientation === 'maximized' ? '3' : '2')};
@@ -202,7 +223,7 @@ const Status = styled.div`
align-items: center;
`;
-const Time = styled.div<{ orientation?: string }>`
+const Time = styled.div`
display: ${(props) => (props.orientation === 'maximized' ? 'flex' : 'none')};
flex-direction: row;
justify-content: center;
@@ -216,23 +237,31 @@ const Icon = styled.img`
align-self: center;
`;
-const TimeText = styled.div<{ status?: string }>`
+const TimeText = styled.div`
font-weight: 500;
font-size: 14px;
line-height: 150%;
- color: ${(props) => (props.status === 'Live' ? '#fff' : '#71717A')};
+ color: ${(props) =>
+ props.status === 'Live'
+ ? `${props.theme.titleTextColor}`
+ : `${props.theme.textColorSecondary}`};
`;
-const InviteButton = styled.button<{ status?: string }>`
+const InviteButton = styled.button`
display: flex;
justify-content: center;
align-items: center;
height: 36px;
width: 100%;
- color: ${(props) => (props.status === 'Live' ? '#FFF' : '#8B5CF6')};
+ color: ${(props) =>
+ props.status === 'Live'
+ ? `${props.theme.titleTextColor}`
+ : `${props.theme.btnColorPrimary}`};
border-radius: 8px;
border: ${(props) =>
- props.status === 'Live' ? '1px solid #FFF' : '1px solid #8B5CF6'};
+ props.status === 'Live'
+ ? `1px solid ${props.theme.titleTextColor}`
+ : `1px solid ${props.theme.btnColorPrimary}`};
background: transparent;
cursor: pointer;
`;
diff --git a/packages/uiweb/src/lib/components/space/SpaceBanner/SpaceBannerLoadingSkeleton.tsx b/packages/uiweb/src/lib/components/space/SpaceBanner/SpaceBannerLoadingSkeleton.tsx
index 013d43705..f52e29e9f 100644
--- a/packages/uiweb/src/lib/components/space/SpaceBanner/SpaceBannerLoadingSkeleton.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceBanner/SpaceBannerLoadingSkeleton.tsx
@@ -33,6 +33,7 @@ const SkeletonContainer = styled.div`
border-radius: 17px;
border: 1px solid lightgrey;
position: relative;
+ width: inherit;
&:after {
content: '';
diff --git a/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWButton/SCWButton.tsx b/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWButton/SCWButton.tsx
index ee1244992..d7d105731 100644
--- a/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWButton/SCWButton.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWButton/SCWButton.tsx
@@ -3,6 +3,7 @@ import styled from 'styled-components';
import { ISpacesTheme } from '../../theme';
import { ThemeContext } from '../../theme/ThemeProvider';
+import { SpacesLogo } from '../../../../icons/SpacesLogo';
export interface ISCWButtonProps { // Space Creation Widget Button Interface
btnText?: string;
@@ -14,7 +15,7 @@ export interface ISCWButtonProps { // Space Creation Widget Button Interface
const defaultProps: ISCWButtonProps = {
btnText: 'Create your Space',
customStyle: {
- padding: '20px',
+ padding: '14px 20px',
borderRadius: '12px',
border: '0px solid transparent',
fontSize: '1rem',
@@ -23,7 +24,7 @@ const defaultProps: ISCWButtonProps = {
export const SCWButton: React.FC = (props) => {
const { btnText, customStyle, onCreate } = props;
-
+
const theme = useContext(ThemeContext);
return (
@@ -33,7 +34,10 @@ export const SCWButton: React.FC = (props) => {
theme={theme}
onClick={onCreate}
>
- {btnText}
+
+
+ {btnText}
+
)
@@ -46,12 +50,21 @@ const CreateButton = styled.button`
border: ${props => props.customStyle.border};
font-size: ${props => props.customStyle.fontSize};
- background-image: ${(props) => props.theme.titleBg};
+ background: ${(props) => props.theme.btnColorPrimary};
color: ${(props) => props.theme.titleTextColor};
+ display: flex;
+ align-items: center;
+
+ font-family: 'Strawford';
+
cursor: pointer;
`;
+const BtnText = styled.div`
+ margin-left: 6px;
+`;
+
SCWButton.defaultProps = defaultProps;
export default SCWButton;
diff --git a/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWCreateModal/SCWCreateModal.tsx b/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWCreateModal/SCWCreateModal.tsx
index 5054e6235..572a236b3 100644
--- a/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWCreateModal/SCWCreateModal.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWCreateModal/SCWCreateModal.tsx
@@ -1,5 +1,5 @@
-import React, { MouseEventHandler } from 'react'
-import styled from 'styled-components'
+import React, { MouseEventHandler, useContext } from 'react'
+import styled, { ThemeProvider } from 'styled-components'
import { Modal } from '../../reusables/Modal'
import { Button } from '../../reusables/Button';
@@ -7,6 +7,7 @@ import { ModalHeader } from '../../reusables/ModalHeader';
import { TextInputWithCounter } from '../../reusables/TextInput';
import { CalendarPurple } from '../../../../icons/CalendarPurple';
+import { ThemeContext } from '../../theme/ThemeProvider';
export interface ISCWCModalProps { // Space Creation Widget Create Modal Interface
isInviteVisible?: any;
@@ -21,7 +22,8 @@ export interface ISCWCModalProps { // Space Creation Widget Create Modal Interfa
}
export const SCWCreateModal: React.FC = (props) => {
- const {
+ const theme = useContext(ThemeContext);
+ const {
isInviteVisible, closeCreateModal, handleNameChange,
handleDescriptionChange, nameValue, descriptionValue,
isDescriptionEnabled, isScheduleVisible, onClose,
@@ -29,10 +31,11 @@ export const SCWCreateModal: React.FC = (props) => {
const secBtn = {
background: 'transparent',
- borderColor: '#8b5cf6'
+ borderColor: theme.btnOutline
}
return (
+
@@ -74,11 +77,12 @@ export const SCWCreateModal: React.FC = (props) => {
customStyle={secBtn}
onClick={isScheduleVisible}
>
-
+
+
)
}
@@ -87,4 +91,4 @@ const ButtonContainer = styled.div`
display: flex;
justify-content: space-between;
width: 100%;
-`;
\ No newline at end of file
+`;
diff --git a/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWInviteModal/SCWInviteModal.tsx b/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWInviteModal/SCWInviteModal.tsx
index 94c8ac684..1f81b2682 100644
--- a/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWInviteModal/SCWInviteModal.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SCWInviteModal/SCWInviteModal.tsx
@@ -1,6 +1,6 @@
/* eslint-disable no-prototype-builtins */
-import React, { useState, MouseEventHandler, useContext, useEffect } from 'react'
-import styled from 'styled-components'
+import React, { useState, MouseEventHandler, useContext } from 'react'
+import styled, { ThemeProvider } from 'styled-components'
import * as PushAPI from '@pushprotocol/restapi';
import { ModalHeader } from '../../reusables/ModalHeader';
@@ -10,14 +10,22 @@ import { SearchInput } from '../../reusables/SearchInput';
import { ProfileContainer } from '../../reusables/ProfileContainer';
import { ThemeContext } from '../../theme/ThemeProvider';
import { Spinner } from '../../reusables/Spinner';
+import { createIcon } from '../../helpers/blockies';
import CircularProgressSpinner from '../../../loader/loader';
import { useSpaceData } from '../../../../hooks';
import SettingsIcon from '../../../../icons/settingsBlack.svg';
+import { SettingsLogo } from '../../../../icons/SettingsLogo';
import { Image } from '../../../../config';
-import { createIcon } from '../../helpers/blockies';
+
+export interface ICustomSearchResult {
+ account: string;
+ name?: string;
+ handle?: string;
+ image?: string; // dataURL as string
+}
export interface ISCWIModalProps { // Space Creation Widget Create Modal Interface
closeInviteModal?: MouseEventHandler;
@@ -32,12 +40,8 @@ export interface ISCWIModalProps { // Space Creation Widget Create Modal Interfa
setAdminsList?: any;
adminsAddressList?: any;
setAdminsAddressList?: any;
- onClose: () => void;
-}
-
-interface User {
- handle: string;
- name: string;
+ onClose: any;
+ btnString?: string;
}
export const SCWInviteModal: React.FC = (props) => {
@@ -51,17 +55,18 @@ export const SCWInviteModal: React.FC = (props) => {
setAdminsList,
adminsAddressList,
setAdminsAddressList,
- onClose
+ onClose,
+ btnString,
} = props;
const theme = useContext(ThemeContext);
- const { env, account } = useSpaceData();
+ const { env, account, customSearch } = useSpaceData();
const [invitedMember, setInvitedMember] = useState('')
const [loadingAccount, setLoadingAccount] = useState(false)
const [searchedUser, setSearchedUser]= useState({});
- const [errorMsg, setErrorMsg] = useState('');
+ const [errorMsg, setErrorMsg] = useState('');
const searchMember = async (event: any) => {
setInvitedMember(event.target.value)
@@ -70,7 +75,36 @@ export const SCWInviteModal: React.FC = (props) => {
handleError('Cannot add Host to members');
return;
}
-
+
+ if (customSearch) {
+ const customUserResponse = customSearch(event.target.value);
+
+ const hasAccount = (obj: any, uniqueKey: string) => {
+ const keys = Object.keys(obj);
+ return keys.length < 4 && keys[0] === uniqueKey;
+ }
+
+ if(hasAccount(customUserResponse, 'account')) {
+ const icon = createIcon({
+ seed: customUserResponse.account,
+ size: 10,
+ scale: 3,
+ });
+
+ const searchedUser = {
+ handle: customUserResponse.account,
+ name: customUserResponse.account,
+ image: icon.toDataURL(),
+ };
+
+ setSearchedUser(searchedUser)
+ } else {
+ setSearchedUser(customUserResponse);
+ }
+
+ return;
+ }
+
try {
setLoadingAccount(true);
const response = await PushAPI.user.get({
@@ -86,7 +120,7 @@ export const SCWInviteModal: React.FC = (props) => {
});
const nullUser = {
- walletAddress: event.target.value,
+ handle: event.target.value,
name: event.target.value,
image: icon.toDataURL(),
};
@@ -131,7 +165,7 @@ export const SCWInviteModal: React.FC = (props) => {
setInvitedAddressList([...invitedAddressList, user.did.substring(7)])
setInvitedMembersList([...invitedMembersList, user]);
} else {
- setInvitedAddressList([...invitedAddressList, user.walletAddress])
+ setInvitedAddressList([...invitedAddressList, user.handle])
setInvitedMembersList([...invitedMembersList, user]);
}
@@ -144,7 +178,7 @@ export const SCWInviteModal: React.FC = (props) => {
setAdminsAddressList([...adminsAddressList, user.did.substring(7)]);
} else {
setAdminsList([...adminsList, user])
- setAdminsAddressList([...adminsAddressList, user.walletAddress]);
+ setAdminsAddressList([...adminsAddressList, user.handle]);
}
const updatedArray = invitedMembersList.filter((item: any) => item !== user)
@@ -154,7 +188,7 @@ export const SCWInviteModal: React.FC = (props) => {
const updateAddressArray = invitedAddressList.filter((item: string) => item !== user.did.substring(7))
setInvitedAddressList(updateAddressArray);
} else {
- const updateAddressArray = invitedAddressList.filter((item: string) => item !== user.walletAddress)
+ const updateAddressArray = invitedAddressList.filter((item: string) => item !== user.handle)
setInvitedAddressList(updateAddressArray);
}
@@ -169,7 +203,7 @@ export const SCWInviteModal: React.FC = (props) => {
const updateAddressArray = invitedAddressList.filter((item: string) => item !== user.did.substring(7))
setInvitedAddressList(updateAddressArray);
} else {
- const updateAddressArray = invitedAddressList.filter((item: string) => item !== user.walletAddress)
+ const updateAddressArray = invitedAddressList.filter((item: string) => item !== user.handle)
setInvitedAddressList(updateAddressArray);
}
};
@@ -182,15 +216,13 @@ export const SCWInviteModal: React.FC = (props) => {
const updateAdminAddressArray = adminsAddressList.filter((item: string) => item !== user.did.substring(7))
setAdminsAddressList(updateAdminAddressArray);
} else {
- const updateAddressArray = adminsAddressList.filter((item: string) => item !== user.walletAddress)
+ const updateAddressArray = adminsAddressList.filter((item: string) => item !== user.handle)
setAdminsAddressList(updateAddressArray);
}
};
- const tempImageUrl = "https://imgv3.fotor.com/images/blog-richtext-image/10-profile-picture-ideas-to-make-you-stand-out.jpg";
-
return (
-
+
@@ -214,11 +246,10 @@ export const SCWInviteModal: React.FC = (props) => {
{
Object.keys(searchedUser).length === 0 ?
null
- : searchedUser.hasOwnProperty('walletAddress') ?
+ : searchedUser.hasOwnProperty('handle') ?
Add +}
@@ -228,7 +259,6 @@ export const SCWInviteModal: React.FC = (props) => {
: Add +}
@@ -244,22 +274,17 @@ export const SCWInviteModal: React.FC = (props) => {
Invited Members {invitedMembersList.length}
{
invitedMembersList.map((item: any) => {
- if (item.hasOwnProperty('walletAddress')) {
+ if (item.hasOwnProperty('handle')) {
return
-
+
}
- // btnCallback={() => handleDeleteInvitedUser(item)}
removeCallback={() => handleDeleteInvitedUser(item)}
promoteCallback={() => handlePromoteToAdmin(item)}
border
@@ -272,14 +297,9 @@ export const SCWInviteModal: React.FC = (props) => {
imageUrl={item.profile.picture}
contBtn={
-
+
}
- // btnCallback={() => handleDeleteInvitedUser(item)}
removeCallback={() => handleDeleteInvitedUser(item)}
promoteCallback={() => handlePromoteToAdmin(item)}
border
@@ -297,22 +317,17 @@ export const SCWInviteModal: React.FC = (props) => {
Speakers {adminsList.length}
{
adminsList.map((item: any) => {
- if (item.hasOwnProperty('walletAddress')) {
+ if (item.hasOwnProperty('handle')) {
return
-
+
}
- // btnCallback={() => handleDeleteInvitedUser(item)}
removeCallback={() => handleDeleteInvitedAdmin(item)}
// promoteCallback={() => handlePromoteToAdmin(item)}
border
@@ -325,14 +340,9 @@ export const SCWInviteModal: React.FC = (props) => {
imageUrl={item.profile.picture}
contBtn={
-
+
}
- // btnCallback={() => handleDeleteInvitedUser(item)}
removeCallback={() => handleDeleteInvitedAdmin(item)}
// promoteCallback={() => handlePromoteToAdmin(item)}
border
@@ -351,11 +361,11 @@ export const SCWInviteModal: React.FC = (props) => {
{
isLoading ?
- : 'Create Space'
+ : btnString ?? 'Create Space'
}
-
+
)
}
@@ -406,13 +416,13 @@ const ContBtn = styled.button`
line-height: 18px;
width: max-content;
background: transparent;
- color: #8B5CF6;
+ color: ${props => props.theme.btnColorPrimary};
border-radius: 6px;
font-weight: 500;
font-size: 12px;
padding: 4px 8px;
border-radius: 8px;
- border: 1px solid #8B5CF6;
+ border: 1px solid ${props => props.theme.btnOutline};
cursor: pointer;
`;
@@ -420,4 +430,4 @@ const ErrorMessage = styled.div`
color: #E93636;
font-size: 14px;
margin-bottom: 8px;
-`;
\ No newline at end of file
+`;
diff --git a/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SpaceCreationWidget.tsx b/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SpaceCreationWidget.tsx
index 54bee046c..0ce55df81 100644
--- a/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SpaceCreationWidget.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceCreationWidget/SpaceCreationWidget.tsx
@@ -7,14 +7,14 @@ import { SCWScheduleModal } from './SCWScheduleModal/SCWScheduleModal';
import { SCWInviteModal } from './SCWInviteModal/SCWInviteModal';
import { SCWButton } from './SCWButton';
-import { useSpaceData } from '../../../hooks';
+import { useSpaceData, usePushSpaceSocket } from '../../../hooks';
export interface ISpaceCreateWidgetProps {
- CustomComponent?: any;
+ children?: React.ReactNode;
}
export const SpaceCreationWidget:React.FC = (props) => {
- const { CustomComponent } = props;
+ const { children } = props;
const [isCreateModalVisible, setIsCreateModalVisible] = useState(false);
const [isScheduleModalVisible, setIsScheduleModalVisible] = useState(false);
@@ -35,7 +35,9 @@ export const SpaceCreationWidget:React.FC = (props) =>
time: Date.now(),
})
- const { signer, env, account } = useSpaceData();
+ const { signer, env, account, pgpPrivateKey } = useSpaceData();
+
+ usePushSpaceSocket({ account, env });
const handleNameChange = (event: any) => {
setSpaceState((prevState) => ({...prevState, spaceName: event.target.value}))
@@ -99,8 +101,8 @@ export const SpaceCreationWidget:React.FC = (props) =>
time: Date.now(),
})
}
-
- const testCreateSpace = async () => {
+
+ const createSpace = async () => {
const spaceCreate = {
spaceName: spaceState.spaceName.length === 0 ? `${account}'s Space` : spaceState.spaceName,
spaceDescription: 'Push Space',
@@ -110,13 +112,13 @@ export const SpaceCreationWidget:React.FC = (props) =>
isPublic: true,
scheduleAt: spaceState.time > Date.now() ? new Date(spaceState.time) : new Date(Date.now() + 120000),
signer: signer as PushAPI.SignerType,
- env
+ env,
+ ...(pgpPrivateKey && pgpPrivateKey !== '' && { pgpPrivateKey }), // Conditionally add pgpPrivateKey
}
try {
setLoading(true);
const response = await PushAPI.space.create(spaceCreate);
-
console.log(response);
} catch (e:any) {
console.error(e.message);
@@ -128,65 +130,65 @@ export const SpaceCreationWidget:React.FC = (props) =>
};
return (
-
- {
- CustomComponent
- ?
-
- :
-
- }
-
- {isCreateModalVisible &&
-
- }
-
- {isScheduleModalVisible &&
-
- }
-
- {isInviteModalVisible &&
-
- }
-
+
+
+ {!children &&
+
+ }
+
+ {children && {children}
}
+
+ {isCreateModalVisible &&
+
+ }
+
+ {isScheduleModalVisible &&
+
+ }
+
+ {isInviteModalVisible &&
+
+ }
+
+
)
}
const SCWContainer = styled.div`
- font-family: 'Strawford'; // update to fontFamily theme
-`;
\ No newline at end of file
+ font-family: 'Strawford'; // update to fontFamily theme
+`;
diff --git a/packages/uiweb/src/lib/components/space/SpaceFeed/SpaceFeed.tsx b/packages/uiweb/src/lib/components/space/SpaceFeed/SpaceFeed.tsx
index 1cb55ff6f..efb7035e8 100644
--- a/packages/uiweb/src/lib/components/space/SpaceFeed/SpaceFeed.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceFeed/SpaceFeed.tsx
@@ -1,5 +1,5 @@
-import React, { useState } from 'react';
-import styled from 'styled-components';
+import React, { useContext, useState } from 'react';
+import styled, { ThemeProvider } from 'styled-components';
import { SpaceIFeeds } from '@pushprotocol/restapi';
@@ -13,22 +13,26 @@ import {
useMySpaces,
usePopularSpaces,
useSpaceRequests,
+ usePushSpaceSocket,
} from '../../../hooks';
import { ISpacePaginationData } from '../../../context/spacesContext';
import spacesIcon from '../../../icons/Spaces.svg';
+import { ThemeContext } from '../theme/ThemeProvider';
enum OrientationEnums {
Horizontal = 'horizontal',
Vertical = 'vertical',
}
-enum Tabs {
+export enum FeedTabs {
ForYou = 'For You',
Popular = 'Popular',
HostedByYou = 'Hosted by you',
}
+type TabsValues = keyof typeof FeedTabs;
+
enum FilterEnums {
All = 'All',
Live = 'Live',
@@ -38,7 +42,7 @@ export interface ISpaceFeedProps {
orientation?: 'horizontal' | 'vertical';
height?: number;
width?: number;
- sortingOrder?: string[];
+ sortingOrder?: Array;
showTabs?: boolean;
filter?: FilterEnums.All | FilterEnums.Live | FilterEnums.Scheduled;
showFilter?: boolean;
@@ -46,17 +50,18 @@ export interface ISpaceFeedProps {
}
export const SpaceFeed: React.FC = ({
- orientation = 'veritcal',
+ orientation = OrientationEnums.Vertical,
height,
width,
- sortingOrder = [Tabs.Popular, Tabs.ForYou, Tabs.HostedByYou],
+ sortingOrder = ['Popular', 'ForYou', 'HostedByYou'],
showTabs = true,
filter = FilterEnums.All,
showFilter = true,
onBannerClickHandler,
}) => {
- const [tab, setTab] = useState(sortingOrder[0]);
+ const theme = useContext(ThemeContext);
const [filterTab, setFilterTab] = useState(filter);
+ const { selectedFeedTab, setSelectedFeedTab } = useSpaceData();
const {
account,
@@ -66,13 +71,12 @@ export const SpaceFeed: React.FC = ({
setPopularSpaces,
spaceRequests,
setSpaceRequests,
+ env,
} = useSpaceData();
- const listInnerRef = useFeedScroll(mySpaces.apiData?.length);
+ usePushSpaceSocket({ account, env });
- const handleTabChange = (tab: string) => {
- setTab(tab);
- };
+ const listInnerRef = useFeedScroll(mySpaces.apiData?.length);
const handleFilterData = (spacesList: SpaceIFeeds[]) => {
if (filterTab === FilterEnums.All) {
@@ -91,17 +95,17 @@ export const SpaceFeed: React.FC = ({
};
const handleMySpacesFilter = (spacesList: SpaceIFeeds[]) => {
- if (tab === Tabs.HostedByYou) {
+ if (selectedFeedTab === FeedTabs.HostedByYou) {
return spacesList.filter(
(space: SpaceIFeeds) =>
- space.spaceInformation?.spaceCreator.slice(7).toUpperCase() ===
+ space.spaceInformation?.spaceCreator?.toUpperCase() ===
account?.toUpperCase()
);
}
- if (tab === Tabs.ForYou) {
+ if (selectedFeedTab === FeedTabs.ForYou) {
return spacesList.filter(
(space: SpaceIFeeds) =>
- space.spaceInformation?.spaceCreator.slice(7).toUpperCase() !==
+ space.spaceInformation?.spaceCreator?.toUpperCase() !==
account?.toUpperCase()
);
} else {
@@ -147,19 +151,17 @@ export const SpaceFeed: React.FC = ({
};
const loadMoreData = async () => {
- if (tab === Tabs.ForYou) {
+ if (selectedFeedTab === FeedTabs.ForYou) {
incrementSpacePage(mySpaces);
}
- if (tab === Tabs.Popular) {
+ if (selectedFeedTab === FeedTabs.Popular) {
incrementSpacePage(popularSpaces);
}
- if (tab === Tabs.HostedByYou) {
+ if (selectedFeedTab === FeedTabs.HostedByYou) {
incrementSpacePage(spaceRequests);
}
};
- console.log(account);
-
const onScroll = () => {
if (listInnerRef.current) {
const { scrollTop } = listInnerRef.current;
@@ -181,7 +183,14 @@ export const SpaceFeed: React.FC = ({
mySpaceLoading || popularSpaceLoading || spaceRequestsLoading;
return (
-
+
+
{orientation === OrientationEnums.Horizontal ? (
{orientation === OrientationEnums.Horizontal
@@ -214,108 +223,81 @@ export const SpaceFeed: React.FC = ({
<>
- {sortingOrder.map((tabName: string) => {
+ {sortingOrder.map((tabName: TabsValues) => {
return (
handleTabChange(tabName)}
+ active={selectedFeedTab === FeedTabs[tabName]}
+ onClick={() => setSelectedFeedTab(FeedTabs[tabName])}
>
- {tabName}
+ {FeedTabs[tabName]}
);
})}
-
- setFilterTab(FilterEnums.All)}
+
+ setFilterTab(FilterEnums.All)}
+ >
+ All
+
+ setFilterTab(FilterEnums.Live)}
+ >
+ Live
+
+ setFilterTab(FilterEnums.Scheduled)}
+ >
+ Scheduled
+
+
+
- All
-
- setFilterTab(FilterEnums.Live)}
- >
- Live
-
- setFilterTab(FilterEnums.Scheduled)}
- >
- Scheduled
-
-
-
-
- {tab === Tabs.ForYou ? (
-
- {mySpaces.apiData &&
- (handleFilterData(
- handleMySpacesFilter(mySpaces.apiData as SpaceIFeeds[])
- ).length === 0 ? (
-
-
- Join a space
-
- Get started by joining a space
-
-
- ) : (
- handleFilterData(
+
+ {selectedFeedTab === FeedTabs.ForYou ? (
+
+ {mySpaces.apiData &&
+ (handleFilterData(
handleMySpacesFilter(mySpaces.apiData as SpaceIFeeds[])
- ).map((space: SpaceIFeeds) => {
- return (
-
- );
- })
- ))}
-
- ) : tab === Tabs.Popular ? (
-
- Popular Spaces
- {popularSpaces &&
- handleFilterData(
- popularSpaces.apiData as SpaceIFeeds[]
- ).map((space: SpaceIFeeds) => {
- return (
-
- );
- })}
-
- ) : (
-
- {mySpaces.apiData &&
- (handleFilterData(
- handleMySpacesFilter(mySpaces.apiData as SpaceIFeeds[])
- ).length === 0 ? (
-
-
- Create a space
-
- Get started by creating a space
-
-
- ) : (
+ ).length === 0 ? (
+
+
+ Join a space
+
+ Get started by joining a space
+
+
+ ) : (
+ handleFilterData(
+ handleMySpacesFilter(
+ mySpaces.apiData as SpaceIFeeds[]
+ )
+ ).map((space: SpaceIFeeds) => {
+ return (
+
+ );
+ })
+ ))}
+
+ ) : selectedFeedTab === FeedTabs.Popular ? (
+
+ {popularSpaces.apiData &&
handleFilterData(
- handleMySpacesFilter(mySpaces.apiData as SpaceIFeeds[])
+ popularSpaces.apiData as SpaceIFeeds[]
).map((space: SpaceIFeeds) => {
return (
= ({
}
/>
);
- })
- ))}
-
- )}
- {loading && }
-
-
- >
- )}
-
+ })}
+
+ ) : (
+
+ {mySpaces.apiData &&
+ (handleFilterData(
+ handleMySpacesFilter(mySpaces.apiData as SpaceIFeeds[])
+ ).length === 0 ? (
+
+
+ Create a space
+
+ Get started by creating a space
+
+
+ ) : (
+ handleFilterData(
+ handleMySpacesFilter(
+ mySpaces.apiData as SpaceIFeeds[]
+ )
+ ).map((space: SpaceIFeeds) => {
+ return (
+
+ );
+ })
+ ))}
+
+ )}
+ {loading && }
+
+
+ >
+ )}
+
+
);
};
@@ -344,16 +357,16 @@ const ScrollContainer = styled.div<{ height?: number; width?: number }>`
width: ${(props) => (props.width ? `${props.width}px` : 'inherit')};
height: ${(props) => (props.height ? `${props.height}px` : 'auto')};
overflow-y: auto;
-}`;
+`;
const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
- background: #ffffff;
- border: 1px solid #dcdcdf;
+ background: ${(props) => props.theme.bgColorPrimary};
+ border: 1px solid ${(props) => props.theme.borderColor};
border-radius: 12px;
padding: 24px 32px;
-}`;
+`;
const Navigation = styled.div<{
showTabs?: boolean;
@@ -365,8 +378,9 @@ const Navigation = styled.div<{
justify-content: space-between;
align-items: center;
width: ${(props) => (props.width ? `${props.width}px` : 'inherit')};
- border-bottom: 1px solid #DCDCDF;
+ border-bottom: 1px solid ${(props) => props.theme.borderColor};
margin-bottom: ${(props) => (props.showFilter ? '0' : '27px')};
+ background: ${(props) => props.theme.bgColorPrimary};
}`;
const NavButtonWrapper = styled.div`
@@ -374,21 +388,25 @@ const NavButtonWrapper = styled.div`
flex-direction: row;
justify-content: space-between;
align-items: center;
-}`;
+`;
const NavButton = styled.button<{ active?: boolean }>`
padding: 10px 30px;
font-weight: 450;
font-size: 14px;
border: none;
- border-bottom: ${(props) => (props.active ? '2px solid #8B5CF6' : 'none')};
+ border-bottom: ${(props) =>
+ props.active ? `2px solid ${props.theme.btnColorPrimary}` : 'none'};
background: none;
- color : ${(props) => (props.active ? '#000000' : '#71717A')};
+ color: ${(props) =>
+ props.active
+ ? `${props.theme.textColorPrimary}`
+ : `${props.theme.textColorSecondary}`};
&:hover {
cursor: pointer;
}
-}`;
+`;
const Spaces = styled.div<{ orientation?: string }>`
display: flex;
@@ -396,23 +414,23 @@ const Spaces = styled.div<{ orientation?: string }>`
props.orientation === 'horizontal' ? 'row' : 'column'};
justify-content: flex-start;
align-items: center;
- background: #ffffff;
+ background: ${(props) => props.theme.bgColorPrimary};
width: ${(props) =>
props.orientation === 'horizontal' ? 'inherit' : '100%'};
height: auto;
gap: 16px;
-}`;
+`;
const PopularSpaces = styled.div`
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
- background: #ffffff;
- width: 100%;
+ background: ${(props) => props.theme.bgColorPrimary};
+ width: 100%;
height: auto;
gap: 16px;
-}`;
+`;
const Text = styled.div`
width: 100%;
@@ -420,17 +438,17 @@ const Text = styled.div`
font-family: 'Strawford';
font-weight: 450;
font-size: 18px;
-}`;
+`;
const Filter = styled.div<{ showFilter?: boolean }>`
display: ${(props) => (props.showFilter ? 'flex' : 'none')};
flex-direction: row;
justify-content: flex-start;
align-items: center;
- background: #ffffff;
+ background: ${(props) => props.theme.bgColorPrimary};
width: 100%;
margin: 22px 0;
-}`;
+`;
const FilterButton = styled.button<{ active: boolean }>`
display: inline-flex;
@@ -439,16 +457,22 @@ const FilterButton = styled.button<{ active: boolean }>`
justify-content: center;
align-items: center;
border-radius: 99px;
- border: 1px solid #C4B5FD;
- background: ${(props) => (props.active ? '#8B5CF6' : '#EDE9FE')};
- color: ${(props) => (!props.active ? '#8B5CF6' : '#FFF')};
+ border: 1px solid ${(props) => props.theme.borderColor};
+ background: ${(props) =>
+ props.active
+ ? `${props.theme.btnColorPrimary}`
+ : `${props.theme.bgColorSecondary}`};
+ color: ${(props) =>
+ props.active
+ ? `${props.theme.titleTextColor}`
+ : `${props.theme.textColorPrimary}`};
margin-right: 8px;
font-size: 14px;
&:hover {
cursor: pointer;
}
-}`;
+`;
const NoSpaces = styled.div`
display: flex;
@@ -456,23 +480,23 @@ const NoSpaces = styled.div`
justify-content: center;
align-items: center;
margin: 130px 0;
-}`;
+`;
const SpacesIcon = styled.img`
width: 36px;
height: 36px;
-}`;
+`;
const NoSpacesTextV1 = styled.div`
font-family: 'Strawford';
font-weight: 450;
font-size: 16px;
- color: #000;
+ color: ${(props) => props.theme.textColorPrimary}};
}`;
const NoSpacesTextV2 = styled.div`
font-family: 'Strawford';
font-weight: 450;
- color: #71717A;
+ color: ${(props) => props.theme.textColorSecondary}};
font-size: 14px;
-}`;
+`;
diff --git a/packages/uiweb/src/lib/components/space/SpaceInvites/SpaceInvites.tsx b/packages/uiweb/src/lib/components/space/SpaceInvites/SpaceInvites.tsx
index 6e808f5fa..7ae369c2a 100644
--- a/packages/uiweb/src/lib/components/space/SpaceInvites/SpaceInvites.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceInvites/SpaceInvites.tsx
@@ -1,67 +1,43 @@
-import React, { useEffect, useState } from 'react';
-import styled from 'styled-components';
+import React, { useContext, useEffect, useState } from 'react';
+import styled, { ThemeProvider } from 'styled-components';
import { Modal } from '../reusables/Modal';
import { Spinner } from '../reusables/Spinner';
import { ModalHeader } from '../reusables/ModalHeader';
-import { useFeedScroll, useSpaceData, useSpaceRequests } from '../../../hooks';
+import {
+ useFeedScroll,
+ useSpaceData,
+ useSpaceRequests,
+ usePushSpaceSocket,
+} from '../../../hooks';
import { SpaceBanner } from '../SpaceBanner';
+import { ISpacesTheme } from '../theme';
+import { ThemeContext } from '../theme/ThemeProvider';
+
export interface ISpaceInvitesProps {
children?: React.ReactNode;
+ actionCallback?: any;
+ onBannerClickHandler?: (arg: string) => void;
}
-// temp
-let spaceId = "";
+interface IThemeProps {
+ theme?: ISpacesTheme;
+}
export const SpaceInvites: React.FC = ({
children,
+ actionCallback,
+ onBannerClickHandler,
}: ISpaceInvitesProps) => {
+ const theme = useContext(ThemeContext);
const [modalOpen, setModalOpen] = useState(false);
const { spaceRequests, setSpaceRequests } = useSpaceData();
const containerRef = useFeedScroll(spaceRequests.apiData?.length);
- const [playBackUrl, setPlayBackUrl] = useState('');
- const {
- spacesObjectRef,
- spaceObjectData,
- initSpaceObject,
- setSpaceWidgetId,
- isSpeaker,
- isListener,
- account,
- } = useSpaceData();
-
- const handleJoinSpace = async (space: any) => {
- await initSpaceObject(space?.spaceId as string);
-
- if (isSpeaker) {
- // create audio stream
- await spacesObjectRef.current.createAudioStream();
- spaceId = space?.spaceId; // temp
- }
- if (isListener) {
- await spacesObjectRef?.current?.join();
- const playBackUrl = spaceObjectData.spaceDescription;
- setPlayBackUrl(playBackUrl);
- handleCloseModal();
- setSpaceWidgetId(space?.spaceId as string);
- console.log('space joined');
- }
- };
+ const { account, env } = useSpaceData();
- useEffect(() => {
- if (!spaceObjectData?.connectionData?.local.stream || !isSpeaker) return;
- const joinSpaceAsSpeaker = async () => {
- console.log('joining as a speaker');
- await spacesObjectRef?.current?.join();
- setSpaceWidgetId(spaceId);
- console.log('space joined');
- handleCloseModal();
- };
- joinSpaceAsSpeaker();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [spaceObjectData?.connectionData?.local.stream]);
+ usePushSpaceSocket({ account, env });
const handleOpenModal = () => {
setModalOpen(true);
@@ -71,6 +47,20 @@ export const SpaceInvites: React.FC = ({
setModalOpen(false);
};
+ const handleCustomClose = () => {
+ if (actionCallback) {
+ actionCallback();
+ }
+
+ setModalOpen(false);
+ };
+
+ const handleClick = (spaceId: string) => {
+ if (onBannerClickHandler) {
+ return onBannerClickHandler(spaceId || '');
+ }
+ };
+
const loadMoreData = () => {
if (
loading === false &&
@@ -78,7 +68,6 @@ export const SpaceInvites: React.FC = ({
spaceRequests.lastPage &&
spaceRequests.currentPage < spaceRequests.lastPage
) {
- console.log('Load More Data');
setSpaceRequests({
currentPage: spaceRequests.currentPage + 1,
lastPage: spaceRequests.lastPage + 1,
@@ -97,7 +86,7 @@ export const SpaceInvites: React.FC = ({
const { loading } = useSpaceRequests(account);
return (
- <>
+
{!children && }
{children && {children}
}
@@ -122,7 +111,10 @@ export const SpaceInvites: React.FC = ({
spaceId={space.spaceId}
orientation="maximized"
isInvite={true}
- onJoin={() => handleJoinSpace(space)}
+ actionCallback={handleCustomClose}
+ onBannerClick={
+ onBannerClickHandler ? handleClick : undefined
+ }
/>
);
})
@@ -132,20 +124,20 @@ export const SpaceInvites: React.FC = ({
)}
- >
+
);
};
-const Button = styled.button`
+const Button = styled.button`
padding: 8px 16px;
- background-color: #8b5cf6;
- color: #fff;
+ background-color: ${(props) => props.theme.btnColorPrimary};
+ color: ${(props) => props.theme.textColorPrimary};
border: none;
border-radius: 4px;
cursor: pointer;
`;
-const ScrollContainer = styled.div`
+const ScrollContainer = styled.div`
max-height: 400px;
width: inherit;
margin-top: 24px;
@@ -161,12 +153,12 @@ const ScrollContainer = styled.div`
-webkit-appearance: none;
width: 4px;
height: auto;
- background: #8b5cf6;
+ background: ${(props) => props.theme.btnColorPrimary};
border-radius: 99px;
}
`;
-const InviteContainer = styled.div`
+const InviteContainer = styled.div`
display: flex;
flex-direction: column;
gap: 16px;
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/EndWidgetContent.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/EndWidgetContent.tsx
new file mode 100644
index 000000000..13785109b
--- /dev/null
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/EndWidgetContent.tsx
@@ -0,0 +1,66 @@
+import React, { MouseEventHandler } from 'react';
+import { Item, Container, Image, Text } from '../../../config';
+import SpaceEnded from '../../../icons/SpaceEnded.svg';
+import { SpaceInfoText } from './ScheduledWidgetContent';
+
+import { ThemeProvider } from 'styled-components';
+import { ThemeContext } from '../theme/ThemeProvider';
+
+interface IEndWidgetContentProps {
+ onClose: MouseEventHandler;
+ toggleWidgetVisibility: () => void;
+}
+
+export const EndWidgetContent: React.FC = ({
+ onClose,
+ toggleWidgetVisibility,
+}) => {
+ const theme = React.useContext(ThemeContext);
+ const handleCloseWidget: React.MouseEventHandler = (
+ event
+ ) => {
+ // Call for hiding the widget
+ toggleWidgetVisibility();
+
+ // Call for running onClose handler from prop
+ onClose(event);
+ };
+
+ return (
+
+
+
+ This Space has ended
+ -
+
+ Close
+
+
+
+
+ );
+};
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/LiveSpaceProfileContainer.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/LiveSpaceProfileContainer.tsx
index c7cf15281..90791a589 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/LiveSpaceProfileContainer.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/LiveSpaceProfileContainer.tsx
@@ -1,3 +1,4 @@
+import React from 'react';
import { IMediaStream } from '@pushprotocol/restapi';
import { Image, Item, Text } from '../../../config';
@@ -5,6 +6,9 @@ import HandIcon from '../../../icons/hand.svg';
import MicOffIcon from '../../../icons/micoff.svg';
import { VideoPlayer } from './VideoPlayer';
+import { ThemeProvider } from 'styled-components';
+import { ThemeContext } from '../theme/ThemeProvider';
+
export interface ILiveSpaceProfileContainerProps {
wallet: string;
isHost?: boolean;
@@ -18,6 +22,7 @@ export interface ILiveSpaceProfileContainerProps {
export const LiveSpaceProfileContainer = (
options: ILiveSpaceProfileContainerProps
) => {
+ const theme = React.useContext(ThemeContext);
const {
wallet,
isHost,
@@ -29,62 +34,64 @@ export const LiveSpaceProfileContainer = (
} = options || {};
return (
- -
-
-
- {wallet.slice(7, 12).concat('...')}
- {stream && }
-
- {requested ? (
-
-
-
- Requested
-
-
-
- ) : (
- -
-
- {isHost ? 'Host' : isSpeaker ? 'Speaker' : 'Listener'}
-
- {!mic && (
+
+
-
+
+
+ {wallet.replace('eip155:', '').slice(0, -36) + '...'}
+ {stream && }
+
+ {requested ? (
+
-
+
+ Requested
+
- )}
-
- )}
-
+
+ ) : (
+ -
+
+ {isHost ? 'Host' : isSpeaker ? 'Speaker' : 'Listener'}
+
+ {!mic && (
+
+ )}
+
+ )}
+
+
);
};
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/LiveWidgetContent.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/LiveWidgetContent.tsx
index 93c056e70..88fa19aff 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/LiveWidgetContent.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/LiveWidgetContent.tsx
@@ -1,37 +1,52 @@
-import React, { useEffect, useState } from 'react';
-import styled from 'styled-components';
+import React, { useEffect, useState, useRef, useContext } from 'react';
+import styled, { keyframes, ThemeProvider } from 'styled-components';
+import { Player } from '@livepeer/react';
+import * as PushAPI from '@pushprotocol/restapi';
+import { SpaceDTO } from '@pushprotocol/restapi';
import { LiveSpaceProfileContainer } from './LiveSpaceProfileContainer';
import { SpaceMembersSectionModal } from './SpaceMembersSectionModal';
+import { createBlockie } from '../helpers/blockies';
+import { ThemeContext } from '../theme/ThemeProvider';
+
+import CircularProgressSpinner from '../../loader/loader';
+
import { Button, Image, Item, Text } from '../../../config';
import MicOnIcon from '../../../icons/micon.svg';
import MicEngagedIcon from '../../../icons/MicEngage.svg';
import MuteIcon from '../../../icons/Muted.svg';
import ShareIcon from '../../../icons/Share.svg';
import MembersIcon from '../../../icons/Members.svg';
-import { SpaceDTO } from '@pushprotocol/restapi';
-
import { useSpaceData } from '../../../hooks';
-import { Player } from '@livepeer/react';
+import { SpaceStatus } from './WidgetContent';
+import { pCAIP10ToWallet } from '../../../helpers';
interface LiveWidgetContentProps {
spaceData?: SpaceDTO;
// temp props only for testing demo purpose for now
isHost?: boolean;
+ setSpaceStatusState: React.Dispatch>;
}
+
export const LiveWidgetContent: React.FC = ({
spaceData,
isHost,
+ setSpaceStatusState,
}) => {
- const tempImageUrl =
- 'https://imgv3.fotor.com/images/blog-richtext-image/10-profile-picture-ideas-to-make-you-stand-out.jpg';
const [showMembersModal, setShowMembersModal] = useState(false);
- const [isMicOn, setIsMicOn] = useState(true);
const [playBackUrl, setPlayBackUrl] = useState('');
+ const [isLoading, setIsLoading] = useState(false);
+ const [isDDOpen, setIsDDOpen] = useState(false);
+
+ const dropdownRef = useRef(null);
+
+ const theme = useContext(ThemeContext);
+
const {
spacesObjectRef,
spaceObjectData,
+ setSpaceObjectData,
isSpeaker,
isListener,
setSpaceWidgetId,
@@ -39,57 +54,116 @@ export const LiveWidgetContent: React.FC = ({
initSpaceObject,
} = useSpaceData();
+ console.log(
+ '🚀 ~ file: LiveWidgetContent.tsx:53 ~ spacesObjectRef:',
+ spacesObjectRef
+ );
+
+ const isMicOn = spaceObjectData?.connectionData?.local?.audio;
+
+ const handleMicState = async () => {
+ await spacesObjectRef?.current?.enableAudio?.({ state: !isMicOn });
+ };
+
+ const handleDDState = () => {
+ setIsDDOpen(!isDDOpen);
+ };
+
const handleJoinSpace = async () => {
if (!spaceData) {
return;
}
+ setIsLoading(!isLoading);
+
await initSpaceObject(spaceData?.spaceId as string);
-
+ // useEffects below will handle the rest
+ };
+
+ const handleEndSpace = async () => {
+ if (!spacesObjectRef?.current) return;
+ await spacesObjectRef?.current?.stop?.();
+ spacesObjectRef.current = null;
+ setSpaceObjectData?.(PushAPI.space.initSpaceData);
+ setSpaceStatusState?.(SpaceStatus.Ended);
+ setIsLoading(false);
+ };
+
+ const handleLeaveSpace = async () => {
+ if (!spacesObjectRef?.current) return;
+ if (isHost || isSpeaker) {
+ await spacesObjectRef?.current?.leave?.();
+ spacesObjectRef.current = null;
+ setSpaceObjectData?.(PushAPI.space.initSpaceData);
+ console.log('Space left');
+ }
if (isListener) {
- console.log('joining as a listner');
- await spacesObjectRef?.current?.join();
- setSpaceWidgetId(spaceData?.spaceId as string);
- console.log('space joined');
+ spacesObjectRef.current = null;
+ setSpaceObjectData?.(PushAPI.space.initSpaceData);
}
+ setIsLoading(false);
};
- useEffect(()=>{
+ // for listener
+ useEffect(() => {
+ const JoinAsListner = async () => {
+ console.log('isListner', isListener);
+ if (
+ isListener &&
+ !isHost &&
+ spaceObjectData.connectionData.local.address
+ ) {
+ console.log('joining as a listener');
+ await spacesObjectRef?.current?.join?.();
+ // setSpaceWidgetId?.(spaceData?.spaceId as string);
+ setIsLoading(!isLoading);
+ console.log('space joined');
+ }
+ };
+ JoinAsListner();
+ }, [isListener]);
+
+ // for speaker
+ useEffect(() => {
const createAudioStream = async () => {
- console.log("isSpeaker", isSpeaker);
- if (isSpeaker) {
+ console.log('isSpeaker', isSpeaker);
+ if (isSpeaker && !spaceObjectData?.connectionData?.local?.stream) {
// create audio stream as we'll need it to start the mesh connection
console.log('creating audio stream');
- await spacesObjectRef.current.createAudioStream();
+ await spacesObjectRef?.current?.createAudioStream?.();
}
- }
+ };
createAudioStream();
- }, [isSpeaker])
+ }, [isSpeaker]);
+ // joining as a speaker
useEffect(() => {
- if (!spaceObjectData?.connectionData?.local.stream || !isSpeaker) return;
+ if (
+ !spaceObjectData?.connectionData?.local?.stream ||
+ !isSpeaker ||
+ (spaceObjectData?.connectionData?.incoming?.length ?? 0) > 1
+ )
+ return;
+
const joinSpaceAsSpeaker = async () => {
console.log('joining as a speaker');
- await spacesObjectRef?.current?.join();
- setSpaceWidgetId(spaceData?.spaceId as string);
+ await spacesObjectRef?.current?.join?.();
+ // setSpaceWidgetId?.(spaceData?.spaceId as string);
+ setIsLoading(!isLoading);
console.log('space joined');
};
joinSpaceAsSpeaker();
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [spaceObjectData?.connectionData?.local.stream]);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [spaceObjectData?.connectionData?.local?.stream]);
useEffect(() => {
- if (!spaceObjectData.spaceDescription) return;
- const playBackUrl = spaceObjectData.spaceDescription;
+ if (!spaceObjectData?.spaceDescription) return;
+ const playBackUrl = spaceObjectData?.spaceDescription;
setPlayBackUrl(playBackUrl);
- }, [spaceObjectData.spaceDescription]);
-
- // console.log('spaceObjectData', spaceObjectData);
- // console.log('playBackUrl', playBackUrl);
- // console.log('isListener', isListener);
+ }, [spaceObjectData?.spaceDescription]);
return (
- <>
+
- = ({
overflowY={'auto'}
alignContent={'flex-start'}
>
- {isSpeaker &&
- spaceObjectData.connectionData.incoming.map((profile) => (
-
- ))}
+ {/* local peer details if speaker or host */}
+ {(isSpeaker || isHost) && (
+
+ )}
+
+ {/* remote peer details if speaker or host */}
+ {(isSpeaker || isHost) &&
+ spaceObjectData?.connectionData?.incoming
+ ?.slice(1)
+ .map((profile) => (
+
+ ))}
+
+ {/* details of everyone in the space if a listner */}
{isListener &&
- spaceObjectData.members.map((profile) => (
-
+ !isHost &&
+ spaceObjectData?.members.map((profile) => (
+
+
+
+ {isDDOpen ? (
+
+ Invite to Speak
+
+ ) : null}
+
))}
-
{isJoined ? (
- = ({
alignItems={'center'}
gap={'8px'}
padding={'10px'}
- onClick={() =>
- isHost || isSpeaker ? setIsMicOn(!isMicOn) : null
- }
+ onClick={() => (isHost || isSpeaker ? handleMicState() : null)}
>
= ({
}
alt="Mic Icon"
/>
-
+
{isHost || isSpeaker
? isMicOn
? 'Speaking'
@@ -176,24 +294,23 @@ export const LiveWidgetContent: React.FC = ({
alt="Share Icon"
/>
- {isListener && playBackUrl.length > 0 && (
-
+ {isListener && !isHost && playBackUrl.length > 0 && (
+
+
+
)}
) : (
@@ -203,13 +320,17 @@ export const LiveWidgetContent: React.FC = ({
border={'none'}
borderRadius={'8px'}
cursor={'pointer'}
- background={
- 'linear-gradient(87.17deg, #EA4EE4 0%, #D23CDF 0.01%, #8B5CF6 100%), linear-gradient(87.17deg, #EA4E93 0%, #DB2777 0.01%, #9963F7 100%), linear-gradient(87.17deg, #B6A0F5 0%, #F46EF7 50.52%, #FFDED3 100%, #FFCFC5 100%), linear-gradient(0deg, #8B5CF6, #8B5CF6), linear-gradient(87.17deg, #B6A0F5 0%, #F46EF7 57.29%, #FF95D5 100%), #FFFFFF'
- }
+ background={`${theme.titleBg}`}
onClick={handleJoinSpace}
>
-
- Join this space
+
+ {isLoading ? : 'Join this Space'}
)}
@@ -219,11 +340,56 @@ export const LiveWidgetContent: React.FC = ({
/>
) : null}
- >
+
);
};
-const PeerPlayer = styled(Player)`
- width: 0;
- height: 0;
-}`;
+const DropDown = styled.div<{ theme?: any; isDDOpen: any }>`
+ position: absolute;
+ top: 0px;
+ right: 0px;
+
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+
+ justify-content: center;
+ align-items: start;
+
+ animation: ${({ isDDOpen }) => (isDDOpen ? fadeIn : fadeOut)} 0.2s ease-in-out;
+ padding: 16px;
+ background: ${(props) => props.theme.bgColorPrimary};
+ color: ${(props) => props.theme.textColorPrimary};
+ border-radius: 16px;
+
+ border: 1px solid ${(props) => props.theme.borderColor};
+`;
+
+const DDItem = styled.div`
+ cursor: pointer;
+`;
+
+const fadeIn = keyframes`
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+`;
+
+const fadeOut = keyframes`
+ from {
+ opacity: 1;
+ }
+ to {
+ opacity: 0;
+ visibility: hidden;
+ }
+`;
+
+const PeerPlayerDiv = styled.div`
+ visibility: hidden;
+ position: absolute;
+ border: 5px solid red;
+`;
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/ScheduledWidgetContent.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/ScheduledWidgetContent.tsx
index 8b041f9c3..19cfa3d12 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/ScheduledWidgetContent.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/ScheduledWidgetContent.tsx
@@ -1,52 +1,70 @@
-import styled from 'styled-components';
+import React, { useEffect, useState } from 'react';
+import styled, { ThemeProvider } from 'styled-components';
import { Button, Container, Image, Item, Text } from '../../../config';
import { formatDate } from '../../../helpers';
+import CircularProgressSpinner from '../../loader/loader';
import SpacesIcon from '../../../icons/Spaces.svg';
import TwitterIcon from '../../../icons/twitterVector.svg';
import CopyIcon from '../../../icons/copyVector.svg';
-import AtIcon from '../../../icons/atVector.svg';
+import LensterIcon from '../../../icons/lensterVector.svg';
import { SpaceDTO } from '@pushprotocol/restapi';
import { useSpaceData } from '../../../hooks';
-import { useEffect, useState } from 'react';
+import { generateLensterShareURL } from '../helpers/share';
+import { ShareConfig } from '../exportedTypes';
+import { SpaceStatus } from './WidgetContent';
+
+import { ThemeContext } from '../theme/ThemeProvider';
+
+enum ShareOptions {
+ Twitter = 'Twitter',
+ Lenster = 'Lenster',
+ CopyShareUrl = 'Copy Link',
+}
+
+export type ShareOptionsValues = keyof typeof ShareOptions;
interface ScheduledWidgetContentProps {
- account?: string;
spaceData?: SpaceDTO;
- shareUrl?: string;
+ share?: ShareConfig;
// temp props only for testing demo purpose for now
isHost?: boolean;
isTimeToStartSpace?: boolean;
isMember?: boolean;
- isSpaceLive: boolean;
- setIsSpaceLive: React.Dispatch>;
+ spaceStatusState: any;
+ setSpaceStatusState: React.Dispatch>;
}
export const ScheduledWidgetContent: React.FC = ({
- account,
spaceData,
- shareUrl,
+ share,
isHost,
isMember,
- isSpaceLive,
- setIsSpaceLive,
+ spaceStatusState,
+ setSpaceStatusState,
}: ScheduledWidgetContentProps) => {
+ const theme = React.useContext(ThemeContext);
+ const { spacesObjectRef, initSpaceObject, spaceObjectData } = useSpaceData();
+
const isTimeToStartSpace = true;
- const {
- spacesObjectRef,
- initSpaceObject,
- spaceObjectData,
- } = useSpaceData();
+
const [isStarted, setIsStarted] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+
+ const { shareUrl, shareOptions = ['Twitter', 'Lenster', 'CopyShareUrl'] } =
+ share || {};
const handleStartSpace = async () => {
+ setIsLoading(!isLoading);
+
console.log('initializing space object');
- await initSpaceObject(spaceData?.spaceId as string);
+ await initSpaceObject?.(spaceData?.spaceId as string);
console.log('creating audio stream');
- await spacesObjectRef.current.createAudioStream();
+ await spacesObjectRef?.current?.createAudioStream?.();
+ setIsLoading(!isLoading);
setIsStarted(true);
console.log('Space Started');
};
@@ -63,6 +81,19 @@ export const ScheduledWidgetContent: React.FC = ({
window.open(tweetUrl, '_blank');
};
+ const handleShareLenster = () => {
+ if (!shareUrl) return;
+ const url = shareUrl;
+ const lensterShareText = 'Join this space';
+
+ const lensterShareUrl = generateLensterShareURL({
+ text: lensterShareText,
+ url,
+ });
+
+ window.open(lensterShareUrl, '_blank');
+ };
+
const handleCopyLink = async () => {
try {
if (!shareUrl) return;
@@ -75,144 +106,165 @@ export const ScheduledWidgetContent: React.FC = ({
}
};
+ const handleShareAction = (shareOption: ShareOptionsValues) => {
+ switch (shareOption) {
+ case ShareOptions.Twitter:
+ handleShareTweet();
+ break;
+ case ShareOptions.Lenster:
+ handleShareLenster();
+ break;
+ default:
+ handleCopyLink();
+ break;
+ }
+ };
+
+ const getShareOptionDetails = (shareOption: ShareOptionsValues) => {
+ let icon = '';
+ let alt = '';
+
+ switch (shareOption) {
+ case ShareOptions.Twitter:
+ icon = TwitterIcon;
+ alt = 'Twitter Icon';
+ break;
+ case ShareOptions.Lenster:
+ icon = LensterIcon;
+ alt = 'Lenster Icon';
+ break;
+ default:
+ icon = CopyIcon;
+ alt = 'Copy Icon';
+ break;
+ }
+
+ return { icon, alt };
+ };
+
useEffect(() => {
async function startSpace() {
- if(isSpaceLive) return;
- if (!spaceObjectData?.connectionData?.local.stream || !isStarted) return;
- await spacesObjectRef.current.start({
- livepeerApiKey: '2638ace1-0a3a-4853-b600-016e6125b9bc',
+ if (spaceStatusState === SpaceStatus.Live) return;
+ if (!spaceObjectData?.connectionData?.local?.stream || !isStarted) return;
+ await spacesObjectRef?.current?.start?.({
+ livepeerApiKey: '6d29b32d-78d4-4a5c-9848-a4a0669eb530',
});
setIsStarted(false);
- setIsSpaceLive && setIsSpaceLive(true);
+ setSpaceStatusState && setSpaceStatusState(SpaceStatus.Live);
}
startSpace();
}, [isStarted]);
- console.log('Rendering ScheduledWidgetContent');
- console.log('isStarted?', isStarted);
-
return (
-
-
- {isHost ? (
- isTimeToStartSpace ? (
- It’s time to start your space
+
+
+
+ {isHost ? (
+ isTimeToStartSpace ? (
+ It’s time to start your space
+ ) : (
+
+ Your space is scheduled.
Share and let people know when to
+ join!
+
+ )
) : (
- Your space is scheduled.
Share and let people know when to
- join!
+ This space will go live on{' '}
+ {formatDate((spaceData?.scheduleAt as any) || new Date())}
- )
- ) : (
-
- This space will go live on{' '}
- {formatDate((spaceData?.scheduleAt as any) || new Date())}
-
- )}
- {isHost && isTimeToStartSpace && (
-
- )}
- {!isHost && !isMember && (
-
- )}
- {!isHost && isMember && (
-
- )}
- {(!isHost || (isHost && !isTimeToStartSpace)) && shareUrl && (
- -
-
-
-
-
-
- Twitter
+ )}
+ {isHost && isTimeToStartSpace && (
+
-
-
-
-
-
- Copy Link
+
+ )}
+ {!isHost && !isMember && (
+
-
-
-
-
-
- Email
+
+ )}
+ {!isHost && isMember && (
+
-
- )}
-
+
+ )}
+ {(!isHost || (isHost && !isTimeToStartSpace)) && shareUrl && (
+ -
+ {shareOptions.map((shareOption) => {
+ const { icon, alt } = getShareOptionDetails(shareOption);
+ return (
+
+ handleShareAction(shareOption)}
+ >
+
+
+
+ {ShareOptions[shareOption]}
+
+
+ );
+ })}
+
+ )}
+
+
);
};
-const SpaceInfoText = styled.span`
+export const SpaceInfoText = styled.span`
font-size: 18px;
font-weight: 600;
text-align: center;
+ color: ${({ theme }) => theme.textColorPrimary};
`;
const ShareLinkItem = styled.div`
@@ -223,7 +275,7 @@ const ShareLinkItem = styled.div`
`;
const ShareLinkButton = styled.button`
- background: #e4e4e7;
+ background: ${({ theme }) => theme.bgColorSecondary};
border-radius: 14px;
padding: 16px;
border: none;
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/SpaceWidget.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/SpaceWidget.tsx
index a93c9054a..12edd0a70 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/SpaceWidget.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/SpaceWidget.tsx
@@ -1,5 +1,5 @@
-import React, { MouseEventHandler, useEffect, useState } from 'react';
-import styled from 'styled-components';
+import React, { MouseEventHandler, useEffect, useState, useRef } from 'react';
+import styled, { ThemeProvider } from 'styled-components';
import { SpaceDTO } from '@pushprotocol/restapi';
import * as PushAPI from '@pushprotocol/restapi';
@@ -7,9 +7,11 @@ import { WidgetContent } from './WidgetContent';
import { WidgetHeader } from './WidgetHeader';
import { ISpaceWidgetProps } from '../exportedTypes';
-import { isLiveSpace, isHostOfSpace, isMemberOfSpace } from './helpers/utils';
+import { isHostOfSpace, isMemberOfSpace } from './helpers/utils';
-import { useSpaceData } from '../../../hooks';
+import { usePushSpaceSocket, useSpaceData } from '../../../hooks';
+
+import { ThemeContext } from '../theme/ThemeProvider';
const DEFAULT_OFFSET = 16;
const DEFAULT_MAXWIDTH = 415;
@@ -23,27 +25,31 @@ export const SpaceWidget: React.FC = (
width,
zIndex = 1000,
spaceId,
- shareUrl,
+ share,
onClose = (() => {
/** */
}) as MouseEventHandler,
isTimeToStartSpace,
} = options || {};
- const [widgetHidden, setWidgetHidden] = useState(!spaceId);
- const { account, spaceObjectData, initSpaceObject, env } = useSpaceData();
+ const spaceStatusRef = useRef();
+
+ const [widgetHidden, setWidgetHidden] = useState(!spaceId);
const [isMinimized, setIsMinimized] = useState(false);
- const { getSpaceInfo, setSpaceInfo } = useSpaceData();
const [spaceData, setSpaceData] = useState();
- const isLive = spaceData && spaceData?.status === 'ACTIVE' ? true : false;
- // console.log('isLiveInWidget', isLive)
+ const { getSpaceInfo, setSpaceInfo, account, env, spaceInfo } =
+ useSpaceData();
+
+ usePushSpaceSocket({ account, env });
useEffect(() => {
if (!spaceId) {
return;
}
+
setWidgetHidden(!spaceId);
+
const fetchData = async () => {
try {
if (getSpaceInfo(spaceId)) {
@@ -59,7 +65,13 @@ export const SpaceWidget: React.FC = (
};
fetchData();
- }, [spaceId]);
+ }, [env, getSpaceInfo, setSpaceInfo, spaceId]);
+
+ useEffect(() => {
+ if (spaceId && spaceInfo[spaceId]) {
+ spaceStatusRef.current = spaceInfo[spaceId].status;
+ }
+ }, [spaceId, spaceInfo]);
// To Be Implemented Later via Meta messages.
// useEffect(() => {
@@ -84,33 +96,37 @@ export const SpaceWidget: React.FC = (
// Implement the SpaceWidget component
return (
-
-
-
-
+
+
+
+
+
+
);
};
@@ -125,14 +141,14 @@ interface WidgetContainerProps {
const Container = styled.div`
font-family: 'Strawford'; // update to fontFamily theme
border-radius: 12px; // update acc to theme
- border: 1px solid #dcdcdf; // update acc to theme
+ border: 1px solid ${(props) => props.theme.borderColor}; // update acc to theme
display: flex;
flex-direction: column;
width: ${(props) => (props.width ? `${props.width}px` : 'auto')};
max-width: ${(props) =>
props.width ? `${props.width}px` : `${DEFAULT_MAXWIDTH}px`};
min-width: 320px;
- background: white;
+ background: ${(props) => props.theme.bgColorPrimary};
justify-content: flex-start;
position: fixed;
bottom: ${(props) => props.bottomOffset}px;
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/SpacesInfo.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/SpacesInfo.tsx
index 15a363597..1cddf6790 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/SpacesInfo.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/SpacesInfo.tsx
@@ -1,104 +1,163 @@
-import React, { useContext, MouseEventHandler } from 'react'
+import React, { useContext, MouseEventHandler, useState } from 'react'
import styled from 'styled-components';
+import * as PushAPI from '@pushprotocol/restapi';
import { Modal } from '../reusables/Modal'
import { ModalHeader } from '../reusables/ModalHeader'
-import { IThemeProviderProps, ThemeContext } from '../theme/ThemeProvider';
+import { ThemeContext } from '../theme/ThemeProvider';
import { Button } from '../reusables/Button';
import { ProfileContainer } from '../reusables/ProfileContainer';
import Accordion from '../reusables/Accordion';
+import { SCWInviteModal } from '../SpaceCreationWidget/SCWInviteModal';
+
+import { useSpaceData } from '../../../hooks';
export interface ISpacesInfoProps {
closeSpacesInfo: MouseEventHandler;
-}
-
-interface IThemeProps {
- theme: IThemeProviderProps;
+ spaceData: any;
}
export const SpacesInfo: React.FC = (props) => {
- const tempImageUrl = "https://imgv3.fotor.com/images/blog-richtext-image/10-profile-picture-ideas-to-make-you-stand-out.jpg";
+ const { spaceData } = props;
const theme = useContext(ThemeContext);
+ const [isInviteVisible, setIsInviteVisible] = useState(false);
+
+ const [invitedMembersList, setInvitedMembersList] = useState([])
+ const [invitedAddressList, setInvitedAddressList] = useState([])
+
+ const [adminsList, setAdminsList] = useState([])
+ const [adminsAddressList, setAdminsAddressList] = useState([])
+
+ const [isLoading, setLoading] = useState(false);
+
+ const { signer, env, pgpPrivateKey } = useSpaceData();
+
const customStyle = {
- color: theme.textColorPrimary,
- background: theme.bgColorPrimary,
- borderColor: theme.borderColor,
+ color: theme?.textColorPrimary,
+ background: theme?.bgColorPrimary,
+ borderColor: theme?.borderColor,
fontWeight: '500',
padding: '14px',
}
- const TEMP_MEMBERS = [
- {
- handle: 's4m4',
- name: 'Samarendra'
- },
- {
- handle: 'aamsa',
- name: 'Aam Saltman'
- },
- {
- handle: 's4m4',
- name: 'Samarendra'
- },
- {
- handle: 'aamsa',
- name: 'Aam Saltman'
- },
- ]
+ const showExplicitInvite: React.MouseEventHandler = () => {
+ setIsInviteVisible(!isInviteVisible);
+ }
+
+ const closeInviteModal = () => {
+ setIsInviteVisible(false);
+ }
+
+ const adminsArray = spaceData?.members?.filter((member: { isSpeaker: boolean; }) => member.isSpeaker);
+
+ const updateSpace = async () => {
+ const spaceUpdate = {
+ spaceName: spaceData?.spaceName,
+ spaceDescription: 'Push Space',
+ listeners: invitedAddressList,
+ spaceImage: 'asd',
+ speakers: adminsAddressList,
+ isPublic: true,
+ scheduleAt: new Date(Date.now() + 120000),
+ signer: signer as PushAPI.SignerType,
+ env,
+ spaceId: spaceData?.spaceId,
+ status: spaceData?.status,
+ ...(pgpPrivateKey && pgpPrivateKey !== '' && { pgpPrivateKey }), // Conditionally add pgpPrivateKey
+ }
+
+ try {
+ setLoading(true);
+ const response = await PushAPI.space.update(spaceUpdate);
+
+ console.log(response);
+ } catch (e:any) {
+ console.error(e.message);
+ } finally {
+ setLoading(false);
+ closeInviteModal();
+ }
+ };
return (
-
+
- larryscruff's space
- Ac orci quam cras in placerat. Sollicitudin tristique sed nisi proin duis.
+ {spaceData?.spaceName}
+ {spaceData?.spaceDescription}
-
- {
- TEMP_MEMBERS.map((item) => {
+
+ {spaceData?.pendingMembers &&
+ spaceData.pendingMembers.map((item: any) => {
return
+ handle={item?.wallet?.substring(7)}
+ name={item?.wallet?.substring(7)}
+ imageUrl={item?.image}
+ />
})
}
-
-
+ {adminsArray &&
+ adminsArray.slice(1).map((item: any) => {
+ return
+ })
+ }
+
+ {
+ isInviteVisible ?
+
+ : null
+ }
)
@@ -107,7 +166,7 @@ export const SpacesInfo: React.FC = (props) => {
/** styling */
const SpacesInfoContainer = styled.div`
- color: black;
+ color: ${(props => props.theme?.textColorPrimary)};
`;
const SpacesDetailsContainer = styled.div`
@@ -119,6 +178,6 @@ const Title = styled.div`
font-weight: 500;
`;
-const Description = styled.div`
- color: ${(props => props.theme.textColorSecondary)};
-`;
\ No newline at end of file
+const Description = styled.div`
+ color: ${(props => props.theme?.textColorSecondary)};
+`;
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/VideoPlayer.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/VideoPlayer.tsx
index 3156b2065..017643c19 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/VideoPlayer.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/VideoPlayer.tsx
@@ -10,16 +10,16 @@ export const VideoPlayer: React.FC = ({ videoCallData }) => {
const incomingVideoRef = useRef(null);
useEffect(() => {
- if (!incomingVideoRef.current) return;
+ if (!incomingVideoRef?.current) return;
const video = incomingVideoRef.current;
video.srcObject = videoCallData;
video.play();
- }, [incomingVideoRef, videoCallData]);
+ }, [incomingVideoRef?.current, videoCallData]);
return ;
};
const Video = styled.video`
- height:0;
- width:0;
-}`;
+ height: 0;
+ width: 0;
+`;
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/WidgetContent.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/WidgetContent.tsx
index a5ee0c810..2e83d2149 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/WidgetContent.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/WidgetContent.tsx
@@ -1,10 +1,12 @@
-import React, { useEffect, useState } from 'react';
+import React, { useEffect, useState, MouseEventHandler } from 'react';
import styled from 'styled-components';
import { LiveWidgetContent } from './LiveWidgetContent';
import { ScheduledWidgetContent } from './ScheduledWidgetContent';
import { SpaceDTO } from '@pushprotocol/restapi';
import { useSpaceData } from '../../../hooks';
+import { EndWidgetContent } from './EndWidgetContent';
+import { ShareConfig } from '../exportedTypes';
const LIVE_WIDGET_CONTENT_FIXED_HEIGHT = '485px';
const SCHEDULED_WIDGET_CONTENT_FIXED_HEIGHT = '350px';
@@ -12,55 +14,81 @@ const SCHEDULED_WIDGET_CONTENT_FIXED_HEIGHT = '350px';
interface WidgetContentProps {
account?: string; //Temp Prop to Test Host functionality
spaceData?: SpaceDTO;
- shareUrl?: string;
+ share?: ShareConfig;
isMinimized: boolean;
// temp props only for testing demo purpose for now
isHost?: boolean;
- isLive: boolean;
+ spaceStatus: any;
isTimeToStartSpace?: boolean;
isMember?: boolean;
+ onClose: MouseEventHandler;
+ toggleWidgetVisibility: () => void;
}
+
+export enum SpaceStatus {
+ Live = 'ACTIVE',
+ Scheduled = 'PENDING',
+ Ended = 'ENDED',
+}
+
export const WidgetContent: React.FC = ({
account,
spaceData,
- shareUrl,
+ share,
isHost,
isTimeToStartSpace,
isMember,
isMinimized,
- isLive,
+ spaceStatus,
+ onClose,
+ toggleWidgetVisibility,
}: WidgetContentProps) => {
- // const { isLive } = useSpaceData();
- console.log('isLiveInWidgetContent', isLive);
- const [isSpaceLive, setIsSpaceLive] = useState(false);
- console.log('isSpaceLive', isSpaceLive);
+ const [spaceStatusState, setSpaceStatusState] = useState(
+ SpaceStatus.Scheduled
+ );
- console.log('Rendering WidgetContent');
useEffect(() => {
- setIsSpaceLive(isLive);
- }, [isLive]);
+ if (spaceStatus === SpaceStatus.Live) {
+ setSpaceStatusState(SpaceStatus.Live);
+ }
+ if (spaceStatus === SpaceStatus.Scheduled) {
+ setSpaceStatusState(SpaceStatus.Scheduled);
+ }
+ if (spaceStatus === SpaceStatus.Ended) {
+ setSpaceStatusState(SpaceStatus.Ended);
+ }
+ }, [spaceStatus]);
return (
- {isSpaceLive ? (
-
- ) : (
+ {spaceStatusState === SpaceStatus.Live ? (
+
+ ) : spaceStatusState === SpaceStatus.Scheduled ? (
+ ) : (
+
)}
@@ -71,10 +99,10 @@ export const WidgetContent: React.FC = ({
const Container = styled.div<{ height: string; isMinimized: boolean }>`
display: flex;
flex-direction: column;
- border-bottom: ${(props) => props.theme.border};
+ border-bottom: ${(props) => props.theme.borderColor};
height: ${(props) => (props.isMinimized ? '0' : props.height)};
- transition: height 200ms ease-out;
+ transition: height 300ms ease-out;
overflow: hidden;
align-items: center;
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/WidgetHeader.tsx b/packages/uiweb/src/lib/components/space/SpaceWidget/WidgetHeader.tsx
index 7a3068ad4..d2ff481f4 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/WidgetHeader.tsx
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/WidgetHeader.tsx
@@ -1,5 +1,10 @@
-import React, { useState, MouseEventHandler, useContext } from 'react';
-import styled from 'styled-components';
+import React, {
+ useState,
+ useEffect,
+ MouseEventHandler,
+ useContext,
+} from 'react';
+import styled, { ThemeProvider } from 'styled-components';
import { Item, Text } from '../../../config';
import { formatDate } from '../../../helpers';
@@ -15,6 +20,8 @@ import { SpacesInfo } from './SpacesInfo';
import { ThemeContext } from '../theme/ThemeProvider';
import { useSpaceData } from '../../../hooks';
+import { SpaceStatus } from './WidgetContent';
+
export interface IWidgetHeaderProps {
onClose: MouseEventHandler;
spaceData?: any;
@@ -23,7 +30,7 @@ export interface IWidgetHeaderProps {
toggleWidgetVisibility: () => void;
// temp props
- isLive?: boolean;
+ spaceStatus?: any;
isHost?: boolean;
}
@@ -34,7 +41,7 @@ export const WidgetHeader: React.FC = ({
setIsMinimized,
toggleWidgetVisibility,
spaceData,
- isLive,
+ spaceStatus,
}: IWidgetHeaderProps) => {
const theme = useContext(ThemeContext);
// const { isLive } = useSpaceData();
@@ -43,6 +50,8 @@ export const WidgetHeader: React.FC = ({
'https://imgv3.fotor.com/images/blog-richtext-image/10-profile-picture-ideas-to-make-you-stand-out.jpg';
const [isSpacesInfoVisible, setIsSpacesInfoVisible] = useState(false);
+ const [isSpaceLive, setIsSpaceLive] = useState(SpaceStatus.Scheduled);
+
const handleCloseWidget: React.MouseEventHandler = (
event
) => {
@@ -62,114 +71,141 @@ export const WidgetHeader: React.FC = ({
setIsSpacesInfoVisible(false);
};
+ useEffect(() => {
+ if (spaceStatus === SpaceStatus.Live) {
+ setIsSpaceLive(SpaceStatus.Live);
+ }
+ if (spaceStatus === SpaceStatus.Scheduled) {
+ setIsSpaceLive(SpaceStatus.Scheduled);
+ }
+ if (spaceStatus === SpaceStatus.Ended) {
+ setIsSpaceLive(SpaceStatus.Ended);
+ }
+ }, [spaceStatus]);
+
return (
-
- {!isLive && (
-
- -
-
-
- -
- {isHost && }
-
-
-
-
- -
- setIsMinimized(!isMinimized)}
- src={isMinimized ? CaretUpIcon : CaretDownIcon}
- alt="Maximize/Minimize icon"
+
+
+ {(isSpaceLive === SpaceStatus.Scheduled ||
+ isSpaceLive === SpaceStatus.Ended) && (
+
-
- )}
-
-
- {spaceData?.spaceName || 'Test Space'}
-
- {isLive && (
- -
-
-
-
-
- -
- setIsMinimized(!isMinimized)}
- src={isMinimized ? CaretUpIcon : CaretDownIcon}
- alt="Maximize/Minimize icon"
- />
+ {isHost && }
+
-
+
+
+ -
+ setIsMinimized(!isMinimized)}
+ src={isMinimized ? CaretUpIcon : CaretDownIcon}
+ alt="Maximize/Minimize icon"
+ />
+
+ -
+
+
+
+ )}
+
+
+ {spaceData?.spaceName || 'Test Space'}
+
+ {isSpaceLive === SpaceStatus.Live && (
-
-
+
-
+
+
+ -
+ setIsMinimized(!isMinimized)}
+ src={isMinimized ? CaretUpIcon : CaretDownIcon}
+ alt="Maximize/Minimize icon"
+ />
+
+ -
+
+
+
+ )}
+
+ {isSpaceLive === SpaceStatus.Scheduled && (
+ -
+
+
-
+ {formatDate(spaceData?.scheduleAt || new Date())}
)}
-
- {!isLive && (
- -
-
-
-
- {formatDate(spaceData?.scheduleAt || new Date())}
-
-
- )}
- {isLive && (
-
- -
-
-
- Live
-
-
- -
-
-
-
+ {isSpaceLive === SpaceStatus.Live && (
+
+
-
+
+
+ Live
+
- {/*
+ -
+
-
+
+
+ {/*
+190 Listeners
*/}
-
-
- )}
- {isSpacesInfoVisible ? (
-
- ) : null}
-
+
+
+ )}
+ {isSpacesInfoVisible ? (
+
+ ) : null}
+
+
);
};
@@ -206,7 +242,7 @@ const Button = styled.button<{
padding: ${(props) => props.padding ?? '0px'};
color: ${(props) => props.color ?? 'inherit'};
margin-left: 10px;
- background: rgba(255, 255, 255, 0.2);
+ background: ${(props) => props.theme.btnColorPrimary}};
border-radius: 6px;
border: none;
cursor: pointer;
diff --git a/packages/uiweb/src/lib/components/space/SpaceWidget/helpers/utils.ts b/packages/uiweb/src/lib/components/space/SpaceWidget/helpers/utils.ts
index bc518b603..7a7532433 100644
--- a/packages/uiweb/src/lib/components/space/SpaceWidget/helpers/utils.ts
+++ b/packages/uiweb/src/lib/components/space/SpaceWidget/helpers/utils.ts
@@ -3,13 +3,13 @@ import { getSpaceStatus } from '../../helpers/space';
export const isHostOfSpace = (account: string, spaceData: SpaceDTO) => {
return (
- account.toUpperCase() === spaceData?.spaceCreator.slice(7).toUpperCase()
+ account.toUpperCase() === spaceData?.spaceCreator.toUpperCase()
);
};
export const isMemberOfSpace = (account: string, spaceData: SpaceDTO) => {
const isMemberArr = spaceData?.members.filter(
- (member) => member.wallet.slice(7).toUpperCase() === account.toUpperCase()
+ (member) => member.wallet.toUpperCase() === account.toUpperCase()
);
return isMemberArr?.length > 0;
};
diff --git a/packages/uiweb/src/lib/components/space/SpacesUI.tsx b/packages/uiweb/src/lib/components/space/SpacesUI.tsx
index 0db6e0989..0d52374ee 100644
--- a/packages/uiweb/src/lib/components/space/SpacesUI.tsx
+++ b/packages/uiweb/src/lib/components/space/SpacesUI.tsx
@@ -4,7 +4,8 @@ import { ISpaceBannerProps, SpaceBanner } from './SpaceBanner';
import { SpaceWidget } from './SpaceWidget';
import { ISpaceFeedProps, SpaceFeed } from './SpaceFeed';
import { ISpaceInvitesProps, SpaceInvites } from './SpaceInvites';
-import { SpaceCreationWidget } from './SpaceCreationWidget';
+import { ISpaceCreateWidgetProps, SpaceCreationWidget } from './SpaceCreationWidget';
+import { ICustomSearchResult } from './SpaceCreationWidget/SCWInviteModal';
import { SignerType } from '../../types';
import { ENV } from '../../config';
@@ -16,12 +17,14 @@ export class SpacesUI {
public signer: SignerType;
public pgpPrivateKey: string;
public env: ENV;
+ public customSearch: ICustomSearchResult | undefined;
constructor(props: ISpacesUIProps) {
this.account = props.account;
this.signer = props.signer;
this.pgpPrivateKey = props.pgpPrivateKey;
this.env = props.env;
+ this.customSearch = props.customSearch;
}
SpaceBanner: React.FC = (options: ISpaceBannerProps) => {
@@ -40,11 +43,11 @@ export class SpacesUI {
useEffect(() => {
setSpaceId(spaceId);
}, [spaceId, setSpaceId]);
-
+
useEffect(() => {
- setSpaceId(spaceWidgetId);
- }, [spaceWidgetId, setSpaceId]);
-
+ if (spaceWidgetId) setSpaceId(spaceWidgetId);
+ }, [spaceWidgetId]);
+
return ;
}
@@ -56,8 +59,8 @@ export class SpacesUI {
return ;
};
- SpaceCreationButtonWidget = () => {
- return
+ SpaceCreationButtonWidget = (options: ISpaceCreateWidgetProps) => {
+ return
}
connectToSockets = () => {
diff --git a/packages/uiweb/src/lib/components/space/exportedTypes.ts b/packages/uiweb/src/lib/components/space/exportedTypes.ts
index 9c4aaf140..e45295ac1 100644
--- a/packages/uiweb/src/lib/components/space/exportedTypes.ts
+++ b/packages/uiweb/src/lib/components/space/exportedTypes.ts
@@ -1,15 +1,23 @@
import { MouseEventHandler } from "react";
+import { ICustomSearchResult } from "./SpaceCreationWidget/SCWInviteModal";
+
import { ENV } from "../../config";
import { SignerType } from "../../types";
+import { ShareOptionsValues } from "./SpaceWidget/ScheduledWidgetContent";
export interface ISpacesUIProps {
account: string;
signer: SignerType;
pgpPrivateKey: string;
env: ENV;
+ customSearch?: ICustomSearchResult | undefined;
}
+export interface ShareConfig {
+ shareUrl?: string;
+ shareOptions?: Array;
+}
export interface ISpaceWidgetProps {
// Add props specific to the SpaceWidget class method
account?: string;
@@ -18,7 +26,7 @@ export interface ISpaceWidgetProps {
zIndex?: number;
spaceId?: string;
width?: number;
- shareUrl?: string;
+ share?: ShareConfig;
onClose?: MouseEventHandler;
// props only for testing demo purpose for now
diff --git a/packages/uiweb/src/lib/components/space/helpers/account.ts b/packages/uiweb/src/lib/components/space/helpers/account.ts
new file mode 100644
index 000000000..916b5bbae
--- /dev/null
+++ b/packages/uiweb/src/lib/components/space/helpers/account.ts
@@ -0,0 +1,16 @@
+import { ENV } from "../../../config";
+
+const ACCOUNT_START_TYPE = {
+ NFT: 'nft',
+ GENERAL: 'eip155'
+}
+
+export const isNftProfile = (account: string) => {
+ return account && account.split(':')[0] === ACCOUNT_START_TYPE.NFT;
+}
+
+export const spaceChainId = (account: string, env: ENV): number => {
+ if (account && isNftProfile(account))
+ return Number(account.split(':')[2]);
+ return env === ENV.PROD ? 1: 5; // Ethereum Mainnet Id
+}
\ No newline at end of file
diff --git a/packages/uiweb/src/lib/components/space/helpers/blockies.ts b/packages/uiweb/src/lib/components/space/helpers/blockies.ts
index 7cfb98eb3..4e68911b4 100644
--- a/packages/uiweb/src/lib/components/space/helpers/blockies.ts
+++ b/packages/uiweb/src/lib/components/space/helpers/blockies.ts
@@ -117,3 +117,13 @@ export function createIcon(opts: Options): HTMLCanvasElement {
return canvas;
}
+
+export function createBlockie(account: string): HTMLCanvasElement {
+ const iconParams = {
+ seed: account,
+ size: 10,
+ scale: 3,
+ };
+
+ return createIcon(iconParams);
+}
diff --git a/packages/uiweb/src/lib/components/space/helpers/share.ts b/packages/uiweb/src/lib/components/space/helpers/share.ts
new file mode 100644
index 000000000..8c5686fa0
--- /dev/null
+++ b/packages/uiweb/src/lib/components/space/helpers/share.ts
@@ -0,0 +1,14 @@
+const LENSTER_URL = 'https://lenster.xyz';
+
+export interface ILensterUrlProps {
+ text: string;
+ url: string;
+}
+export const generateLensterShareURL = ({text, url}: ILensterUrlProps): string => {
+ const encodedText = encodeURIComponent(text);
+ const encodedURL = encodeURIComponent(url);
+
+ const outputURL = `${LENSTER_URL}/?text=${encodedText}&url=${encodedURL}`;
+
+ return outputURL;
+}
diff --git a/packages/uiweb/src/lib/components/space/reusables/Accordion.tsx b/packages/uiweb/src/lib/components/space/reusables/Accordion.tsx
index d962d5fdd..409880a2c 100644
--- a/packages/uiweb/src/lib/components/space/reusables/Accordion.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/Accordion.tsx
@@ -14,7 +14,7 @@ interface IAccordionProps {
const Accordion: React.FC = ({ title, items, children }) => {
const theme = useContext(ThemeContext)
- const [isOpen, setIsOpen] = useState(true);
+ const [isOpen, setIsOpen] = useState(false);
const toggleAccordion = () => {
setIsOpen((prevIsOpen) => !prevIsOpen);
@@ -86,4 +86,4 @@ const Image = styled.img`
height: ${(props: any): string => props.height || '24px'};
width: ${(props: any): string => props.width || '20px'};
align-self: center;
-`;
\ No newline at end of file
+`;
diff --git a/packages/uiweb/src/lib/components/space/reusables/DateTimePicker.tsx b/packages/uiweb/src/lib/components/space/reusables/DateTimePicker.tsx
index 1938bf21b..9cb11ad76 100644
--- a/packages/uiweb/src/lib/components/space/reusables/DateTimePicker.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/DateTimePicker.tsx
@@ -30,7 +30,7 @@ const DateTimePicker: React.FC = (props) => {
const getTime = (hours: number, minutes: number, ampm: string, propsDate: Date) => {
let totalMinutes = hours * 60 + minutes;
-
+
if (ampm === 'PM' && hours !== 12) {
totalMinutes += 12 * 60;
} else if (ampm === 'AM' && hours === 12) {
@@ -48,7 +48,7 @@ const DateTimePicker: React.FC = (props) => {
const hours = parseInt(selectedHours, 10);
const minutes = parseInt(selectedMinutes, 10);
const ampm = selectedAMPM;
-
+
const newTimeEpoch = getTime(hours, minutes, ampm, propsDate);
setTimeHumanReadable(newTimeEpoch);
@@ -118,8 +118,7 @@ const Input = styled.input`
width: 330px;
background: #FFFFFF;
- border: 1px solid ${(props => props.theme.btnOutline)};
- box-shadow: -1px -1px 2px ${(props => props.theme.btnOutline)}, 1px 1px 2px ${(props => props.theme.btnOutline)};
+ border: 2px solid ${(props => props.theme.btnOutline)};
border-radius: 12px;
font-size: 16px;
@@ -137,8 +136,7 @@ const Select = styled.select<{ width?: string }>`
margin-top: 12px;
background: #FFFFFF;
- border: 1px solid ${(props => props.theme.btnOutline)};
- box-shadow: -1px -1px 2px ${(props => props.theme.btnOutline)}, 1px 1px 2px ${(props => props.theme.btnOutline)};
+ border: 2px solid ${(props => props.theme.btnOutline)};
border-radius: 12px;
font-size: 16px;
diff --git a/packages/uiweb/src/lib/components/space/reusables/HostPfpContainer.tsx b/packages/uiweb/src/lib/components/space/reusables/HostPfpContainer.tsx
index 3c410a760..e205ca4a8 100644
--- a/packages/uiweb/src/lib/components/space/reusables/HostPfpContainer.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/HostPfpContainer.tsx
@@ -1,42 +1,61 @@
import React from 'react';
-import styled from 'styled-components';
+import styled, { ThemeProvider } from 'styled-components';
+import { ThemeContext } from '../theme/ThemeProvider';
+
+import { ISpacesTheme } from '../theme';
export interface IHostPfpContainerProps {
name?: string;
handle?: string;
imageUrl?: string;
- statusTheme: "Live" | "Scheduled" | "Ended";
+ statusTheme: 'Live' | 'Scheduled' | 'Ended';
+ imageHeight?: string;
+}
+
+interface IThemeProps {
+ theme?: ISpacesTheme;
+ statusTheme?: string;
imageHeight?: string;
}
export const HostPfpContainer: React.FC = ({
- name = "Host Name",
- handle = "Host Handle",
- imageUrl = "",
+ name = 'Host Name',
+ handle = 'Host Handle',
+ imageUrl = '',
statusTheme,
imageHeight,
}: IHostPfpContainerProps) => {
+ const theme = React.useContext(ThemeContext);
return (
-
-
-
-
-
-
- {name}
- Host
-
- {handle &&
-
- {/* Fetch the handle from Lenster */}@{handle}
-
- }
-
-
+
+
+
+
+
+
+
+ {name}
+
+ Host
+
+
+ {handle && (
+
+ {/* Fetch the handle from Lenster */}@{handle}
+
+ )}
+
+
+
);
};
-const ProfileContainer = styled.div`
+const ProfileContainer = styled.div`
display: flex;
flex-direction: row;
justify-content: space-between;
@@ -48,13 +67,13 @@ const PfpContainer = styled.div`
display: flex;
`;
-const Pfp = styled.img<{ imageHeight?: string }>`
- height: ${(props) => (props.imageHeight ?? '32px')};
- width: ${(props) => (props.imageHeight ?? '32px')};;
+const Pfp = styled.img`
+ height: ${(props) => props.imageHeight ?? '32px'};
+ width: ${(props) => props.imageHeight ?? '32px'};
border-radius: 50%;
`;
-const HostContainer = styled.div`
+const HostContainer = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
@@ -65,7 +84,7 @@ const HostContainer = styled.div`
text-overflow: ellipsis;
`;
-const HostName = styled.div`
+const HostName = styled.div`
display: flex;
flex-direction: row;
font-weight: 600;
@@ -73,13 +92,17 @@ const HostName = styled.div`
width: 100%;
`;
-const Name = styled.span`
+const Name = styled.span`
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
+ color:color: ${(props) =>
+ props.statusTheme === 'Live'
+ ? `${props.theme.titleTextColor}`
+ : `${props.theme.textColorPrimary}`};
`;
-const Host = styled.div<{ statusTheme?: string }>`
+const Host = styled.div`
display: flex;
flex-direction: row;
align-items: center;
@@ -90,16 +113,22 @@ const Host = styled.div<{ statusTheme?: string }>`
height: 19px;
background: ${(props) =>
props.statusTheme === 'Live'
- ? 'rgba(255, 255, 255, 0.2);'
- : 'rgba(139, 92, 246, 0.2)'};
- color: ${(props) => (props.statusTheme === 'Live' ? 'inherit' : '#8B5CF6')};
+ ? `${props.theme.btnOutline}`
+ : `${props.theme.btnOutline}`};
+ color: ${(props) =>
+ props.statusTheme === 'Live'
+ ? 'inherit'
+ : `${props.theme.bgColorSecondary}`};
border-radius: 6px;
font-weight: 500;
font-size: 10px;
`;
-const HostHandle = styled.div<{ statusTheme?: string }>`
- color: ${(props) => (props.statusTheme === 'Live' ? '#F5F5F5E5' : '#71717A')};
+const HostHandle = styled.div`
+ color: ${(props) =>
+ props.statusTheme === 'Live'
+ ? `${props.theme.titleTextColor}`
+ : `${props.theme.textColorSecondary}`};
padding: 0;
font-weight: 450;
font-size: 14px;
diff --git a/packages/uiweb/src/lib/components/space/reusables/Modal.tsx b/packages/uiweb/src/lib/components/space/reusables/Modal.tsx
index b45a54949..6f2115048 100644
--- a/packages/uiweb/src/lib/components/space/reusables/Modal.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/Modal.tsx
@@ -36,7 +36,7 @@ const ClickawayCloseModal = ({ children, clickawayClose, width }: IModalProps) =
export const Modal = ({ clickawayClose, children, width }: IModalProps) => {
const theme = useContext(ThemeContext)
return (
-
+
{clickawayClose ? (
{children}
) : (
@@ -53,7 +53,7 @@ export const Modal = ({ clickawayClose, children, width }: IModalProps) => {
/* styling */
-const ModalOverlay = styled.div`
+const ModalOverlay = styled.div`
position: fixed;
top: 0;
left: 0;
@@ -61,8 +61,10 @@ const ModalOverlay = styled.div`
height: 100%;
background-color: rgba(0, 0, 0, 0.4); /* Black with 40% opacity */
display: flex;
+ color: ${props => props.theme.textColorPrimary ?? '#000'};
justify-content: center;
align-items: center;
+ z-index: 10;
`;
const ModalParent = styled.div`
@@ -80,4 +82,4 @@ const ModalParent = styled.div`
border-radius: 12px;
width: ${(props => props.width ? props.width : 'auto')};
-`;
\ No newline at end of file
+`;
diff --git a/packages/uiweb/src/lib/components/space/reusables/ModalHeader.tsx b/packages/uiweb/src/lib/components/space/reusables/ModalHeader.tsx
index e6df966a6..07ac0d6f6 100644
--- a/packages/uiweb/src/lib/components/space/reusables/ModalHeader.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/ModalHeader.tsx
@@ -1,8 +1,9 @@
-import { MouseEventHandler } from 'react';
-import styled from 'styled-components';
+import { MouseEventHandler, useContext } from 'react';
+import styled, { ThemeProvider } from 'styled-components';
import { CloseSvg } from '../../../icons/CloseSvg';
import { ArrowLeft } from '../../../icons/ArrowLeft';
+import { ThemeContext } from '../theme/ThemeProvider';
export interface IModalHeaderProps {
heading: string;
@@ -12,8 +13,9 @@ export interface IModalHeaderProps {
}
export const ModalHeader = (props: IModalHeaderProps) => {
+ const theme = useContext(ThemeContext);
return (
-
+
{props.backCallback ? (
@@ -23,7 +25,9 @@ export const ModalHeader = (props: IModalHeaderProps) => {
{props.heading}
- {props.headingBadgeNumber && {props.headingBadgeNumber}}
+ {props.headingBadgeNumber && (
+ {props.headingBadgeNumber}
+ )}
{props.closeCallback ? (
@@ -32,7 +36,7 @@ export const ModalHeader = (props: IModalHeaderProps) => {
) : null}
-
+
);
};
@@ -43,6 +47,7 @@ const Header = styled.div`
width: 100%;
margin-bottom: 24px;
+ color: ${(props) => props.theme.textColorPrimary};
`;
const BackBtn = styled.button`
@@ -91,7 +96,7 @@ const NumberBadge = styled.div`
display: flex;
justify-content: center;
align-items: center;
- background:#8B5CF6;
+ background: ${(props) => props.theme.btnColorPrimary};
color: #fff;
border-radius: 8px;
margin-left: 8px;
diff --git a/packages/uiweb/src/lib/components/space/reusables/ParticipantContainer.tsx b/packages/uiweb/src/lib/components/space/reusables/ParticipantContainer.tsx
index 789f016ce..d65eb73c9 100644
--- a/packages/uiweb/src/lib/components/space/reusables/ParticipantContainer.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/ParticipantContainer.tsx
@@ -66,7 +66,7 @@ const ParticipantsIconContainer = styled.div<{ orientation?: string }>`
padding: 0 4px;
}`;
-const ParticipantsIcon = styled.img<{ imageHeight?: any }>`
+const ParticipantsIcon = styled.img<{ imageHeight?: any }>`
height: ${(props) => (props.imageHeight ? props.imageHeight : '31px')};
border-radius: 50%;
@@ -74,19 +74,19 @@ const ParticipantsIcon = styled.img<{ imageHeight?: any }>`
position: relative;
top: 0;
left: 0;
- z-index: 3;
+ // z-index: 3;
}
&.index1 {
position: relative;
top: 0;
left: -50%;
- z-index: 2;
+ // z-index: 2;
}
&.index2 {
position: relative;
top: 0;
left: -100%;
- z-index: 1;
+ // z-index: 1;
}
}`;
diff --git a/packages/uiweb/src/lib/components/space/reusables/ProfileContainer.tsx b/packages/uiweb/src/lib/components/space/reusables/ProfileContainer.tsx
index 4eed4f884..1c49480bd 100644
--- a/packages/uiweb/src/lib/components/space/reusables/ProfileContainer.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/ProfileContainer.tsx
@@ -1,5 +1,5 @@
import React, { useContext, useState, useRef, useEffect } from 'react';
-import styled, { keyframes } from 'styled-components';
+import styled, { keyframes, ThemeProvider } from 'styled-components';
import { ThemeContext } from '../theme/ThemeProvider';
export interface IProfileContainerProps {
@@ -43,15 +43,16 @@ export const ProfileContainer: React.FC = ({
setIsDDOpen(false);
}
};
-
+
document.addEventListener('mousedown', handleOutsideClick);
-
+
return () => {
document.removeEventListener('mousedown', handleOutsideClick);
};
}, []);
return (
+
@@ -90,6 +91,7 @@ export const ProfileContainer: React.FC = ({
: null
}
+
);
};
@@ -104,6 +106,7 @@ const ParentContainer = styled.div<{ border?: boolean }>`
padding: 8px 16px;
border: ${(props => props.border ? '1px solid #E4E4E7' : 'none')};
+ color: ${props => props.theme.textColorPrimary ?? '#000'};
border-radius: 16px;
`;
@@ -162,7 +165,7 @@ const Host = styled.div`
line-height: 18px;
width: max-content;
background: rgba(139, 92, 246, 0.2);
- color: #8B5CF6;
+ color: ${props => props.theme.btnColorPrimary};
border-radius: 6px;
font-weight: 500;
font-size: 12px;
diff --git a/packages/uiweb/src/lib/components/space/reusables/SearchInput.tsx b/packages/uiweb/src/lib/components/space/reusables/SearchInput.tsx
index 5f44c25e2..b0f8539ca 100644
--- a/packages/uiweb/src/lib/components/space/reusables/SearchInput.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/SearchInput.tsx
@@ -1,5 +1,5 @@
import { ChangeEvent, useContext } from 'react';
-import styled from 'styled-components';
+import styled, { ThemeProvider } from 'styled-components';
import { ISpacesTheme } from '../theme';
import { ThemeContext } from '../theme/ThemeProvider';
@@ -21,6 +21,7 @@ export const SearchInput = (props: ISearchInputProps) => {
};
return (
+
@@ -32,6 +33,7 @@ export const SearchInput = (props: ISearchInputProps) => {
+
);
};
@@ -42,7 +44,7 @@ const InputContainer = styled.div`
margin: 16px 0;
- font-family: 'Strawford'; // update to fontFamily theme
+ font-family: 'Strawford'; // update to fontFamily theme
`;
const LabelContainer = styled.div`
@@ -50,6 +52,7 @@ const LabelContainer = styled.div`
justify-content: space-between;
font-weight: 500;
+ color: ${props => props.theme.textColorPrimary ?? '#000'}
`;
const Input = styled.input`
@@ -59,8 +62,7 @@ const Input = styled.input`
width: 330px;
background: #FFFFFF;
- border: 1px solid ${(props => props.theme.btnOutline)};
- box-shadow: -1px -1px 2px ${(props => props.theme.btnOutline)}, 1px 1px 2px ${(props => props.theme.btnOutline)};
+ border: 2px solid ${(props => props.theme.btnOutline)};
border-radius: 12px;
`;
@@ -73,4 +75,4 @@ const CloseBtn = styled.div`
right: 0;
top: 0;
padding: 1.75rem 0.75rem;
-`;
\ No newline at end of file
+`;
diff --git a/packages/uiweb/src/lib/components/space/reusables/Spinner.tsx b/packages/uiweb/src/lib/components/space/reusables/Spinner.tsx
index d635de040..0d975ac6f 100644
--- a/packages/uiweb/src/lib/components/space/reusables/Spinner.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/Spinner.tsx
@@ -1,6 +1,7 @@
import React, { useContext } from 'react';
-import styled, { keyframes } from 'styled-components';
+import styled, { keyframes, ThemeProvider } from 'styled-components';
import { SpinnerSvg } from '../../../icons/SpinnerSvg';
+import { ThemeContext } from '../theme/ThemeProvider';
type SpinnerPropType = {
size?: string;
@@ -11,10 +12,13 @@ type SpinLoaderPropType = {
};
export const Spinner: React.FC = ({ size = 42 }) => {
+ const theme = useContext(ThemeContext);
return (
-
-
-
+
+
+
+
+
);
};
diff --git a/packages/uiweb/src/lib/components/space/reusables/TextInput.tsx b/packages/uiweb/src/lib/components/space/reusables/TextInput.tsx
index d87d90a2d..509945f4d 100644
--- a/packages/uiweb/src/lib/components/space/reusables/TextInput.tsx
+++ b/packages/uiweb/src/lib/components/space/reusables/TextInput.tsx
@@ -1,5 +1,5 @@
import React, { ChangeEvent, useContext } from 'react';
-import styled from 'styled-components';
+import styled, { ThemeProvider } from 'styled-components';
import { ISpacesTheme } from '../theme';
import { ThemeContext } from '../theme/ThemeProvider';
@@ -24,6 +24,7 @@ export const TextInputWithCounter = (props: ITextInputProps) => {
};
return (
+
@@ -31,6 +32,7 @@ export const TextInputWithCounter = (props: ITextInputProps) => {
+
);
};
@@ -41,7 +43,7 @@ const InputContainer = styled.div`
margin: 16px 0;
- font-family: 'Strawford'; // update to fontFamily theme
+ font-family: 'Strawford'; // update to fontFamily theme
`;
const LabelContainer = styled.div`
@@ -49,6 +51,7 @@ const LabelContainer = styled.div`
justify-content: space-between;
font-weight: 500;
+ color: ${props => props.theme.textColorPrimary ?? '#000'}
`;
const Input = styled.input`
@@ -58,14 +61,13 @@ const Input = styled.input`
width: 330px;
background: #FFFFFF;
- border: 1px solid ${(props => props.theme.btnOutline)};
- box-shadow: -1px -1px 2px ${(props => props.theme.btnOutline)}, 1px 1px 2px ${(props => props.theme.btnOutline)};
+ border: 2px solid ${(props => props.theme.btnOutline)};
border-radius: 12px;
- font-family: 'Strawford'; // update to fontFamily theme
+ font-family: 'Strawford'; // update to fontFamily theme
font-size: 14px;
`;
const CharCounter = styled.div`
color: ${(props => props.theme.textColorSecondary)};
-`;
\ No newline at end of file
+`;
diff --git a/packages/uiweb/src/lib/components/space/theme/index.ts b/packages/uiweb/src/lib/components/space/theme/index.ts
index 99c70253e..52c116397 100644
--- a/packages/uiweb/src/lib/components/space/theme/index.ts
+++ b/packages/uiweb/src/lib/components/space/theme/index.ts
@@ -36,7 +36,7 @@ export const lightTheme: ISpacesTheme = {
containerBorderRadius: '12px',
statusColorError: '#E93636',
statusColorSuccess: '#30CC8B',
- iconColorPrimary: '#82828A'
+ iconColorPrimary: '#82828A',
};
export const darkTheme: ISpacesTheme = {
@@ -54,5 +54,5 @@ export const darkTheme: ISpacesTheme = {
containerBorderRadius: '12px',
statusColorError: '#E93636',
statusColorSuccess: '#30CC8B',
- iconColorPrimary: '#71717A'
+ iconColorPrimary: '#71717A',
};
diff --git a/packages/uiweb/src/lib/context/chatAndNotification/chat/chatMainStateContext.tsx b/packages/uiweb/src/lib/context/chatAndNotification/chat/chatMainStateContext.tsx
index 033be516f..53dcfe7eb 100644
--- a/packages/uiweb/src/lib/context/chatAndNotification/chat/chatMainStateContext.tsx
+++ b/packages/uiweb/src/lib/context/chatAndNotification/chat/chatMainStateContext.tsx
@@ -26,6 +26,10 @@ export type ChatMainStateContextType = {
setConnectedProfile: (connectedProfile: IUser) => void;
searchedChats: ChatFeedsType | null;
setSearchedChats: (chats:ChatFeedsType | null) => void;
+ finishedFetchingChats:boolean;
+ finishedFetchingRequests:boolean;
+ setFinishedFetchingChats: (flag: boolean) => void;
+ setFinishedFetchingRequests: (flag: boolean) => void;
}
export const ChatMainStateContext = createContext({} as ChatMainStateContextType);
@@ -38,6 +42,9 @@ const [requestsFeed,setRequestsFeed] =useState({} as ChatFeedsTyp
const [chats,setChats] = useState