From 19451df1c94cba680d785fd194f1443cca0f32e4 Mon Sep 17 00:00:00 2001 From: Rohit Malhotra Date: Fri, 16 Aug 2024 14:10:47 +0530 Subject: [PATCH 1/5] updated prod nft whitelist file (#1808) --- src/config/alphaAccessNft/whitelist.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/config/alphaAccessNft/whitelist.json b/src/config/alphaAccessNft/whitelist.json index 805947f8cb..42b118d01c 100644 --- a/src/config/alphaAccessNft/whitelist.json +++ b/src/config/alphaAccessNft/whitelist.json @@ -5196,5 +5196,11 @@ "0x12a908c746f74bff8d9b4528f2357aea73cb1437", "0x4073f3a5109a3168676bd7b18143ae784acbf4a0", "0x2895be25c83f3702fd7bbfeb620edb285227c53e", - "0x86edc5dde41deb4ebd81b1b4e27e59a2868da200" + "0x86edc5dde41deb4ebd81b1b4e27e59a2868da200", + "0x0b340c5cbfb62b36dcb793e542d86dfc20d9b1ba", + "0x1588e9a8cc4cf45e02d4f54e3cd174b0dc1c9afb", + "0x21f7116f42a9c155e7ee3c728e35b90d1b2cb17b", + "0x418be23ceafe3af2f93927f619d2b61b71057ff5", + "0x99a208eb775b13ae29c4494d32ffac3ee397dfa5", + "0xc58088e74aee082a28f298b8f1b08be2972cdf3e" ] From 0e38437c0ebca9647adbe89cd281b037454a827f Mon Sep 17 00:00:00 2001 From: Monalisha Mishra <42746736+mishramonalisha76@users.noreply.github.com> Date: Fri, 16 Aug 2024 17:01:04 +0530 Subject: [PATCH 2/5] refetch all subscriptions added (#1810) --- .../components/FeaturedChannelsListItem.tsx | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/modules/dashboard/components/FeaturedChannelsListItem.tsx b/src/modules/dashboard/components/FeaturedChannelsListItem.tsx index 113b5a044f..76f0f7ae8a 100644 --- a/src/modules/dashboard/components/FeaturedChannelsListItem.tsx +++ b/src/modules/dashboard/components/FeaturedChannelsListItem.tsx @@ -13,7 +13,16 @@ import { useAccount } from 'hooks'; import { formatSubscriberCount } from '../Dashboard.utils'; // Components -import { Box, Button, CaretDown, Ethereum, NotificationMobile, Skeleton, Text, TickDecoratedCircleFilled } from 'blocks'; +import { + Box, + Button, + CaretDown, + Ethereum, + NotificationMobile, + Skeleton, + Text, + TickDecoratedCircleFilled, +} from 'blocks'; import { SubscribeChannelDropdown } from 'common/components/SubscribeChannelDropdown'; import { UnsubscribeChannelDropdown } from 'common/components/UnsubscribeChannelDropdown'; import { VerifiedToolTipComponent } from './VerifiedToolTipComponent'; @@ -37,7 +46,7 @@ const FeaturedChannelsListItem: FC = (props) => { /* Fetching Channel Details based on Channel Address */ const { data: channelDetails, isLoading } = useGetChannelDetails(channelAddress); - + const { refetch: refetchAllSubscriptions } = useGetUserSubscriptions(); /* Fetching User Subscribed Channel Details along with user settings */ const { data: userSubscription, @@ -52,6 +61,10 @@ const FeaturedChannelsListItem: FC = (props) => { const hasAliasAddress = channelDetails && channelDetails?.alias_address != null && channelDetails?.alias_address != 'NULL'; + const handleRefetch = () => { + refetch(); + refetchAllSubscriptions(); + }; return ( <> = (props) => { > + ) : ( + + + + + + + 1 + + + Sepolia ETH Faucet + + + + + + mintPushToken(1000)} + > + + + 2 + + + Get Testnet Push + + + + )} + + {/* //TODO: This will get changed with the new modal design */} + {isUniswapWidgetModalOpen && ( + + )} + + + ); +}; + +export { TokenFaucet }; \ No newline at end of file diff --git a/src/common/components/UnsubscribeChannelDropdown.tsx b/src/common/components/UnsubscribeChannelDropdown.tsx index 50441cf136..c3b1e03c60 100644 --- a/src/common/components/UnsubscribeChannelDropdown.tsx +++ b/src/common/components/UnsubscribeChannelDropdown.tsx @@ -17,7 +17,8 @@ import { convertAddressToAddrCaip } from 'helpers/CaipHelper'; import { notifUserSettingFormatString, userSettingsFromDefaultChannelSetting } from 'helpers/channel/notifSetting'; // Utility functions -import { ChannelDetailsResponse, useUnsubscribeChannel, useUpdateNotificationSettings } from 'queries'; +import { ChannelDetails } from 'queries'; +import { useUnsubscribeChannel, useUpdateNotificationSettings } from 'queries'; // Components import { ManageSettingsDropdown } from './ManageSettingsDropdown'; @@ -25,7 +26,8 @@ import { UserStoreType } from 'types'; export type UnsubscribeChannelDropdownProps = { children: ReactNode; - channelDetail: ChannelDetailsResponse; + channelDetail: ChannelDetails; + centeronMobile?: boolean; onSuccess: () => void; userSetting?: UserSetting[] | undefined; }; @@ -34,7 +36,7 @@ const UnsubscribeChannelDropdown: FC = ({ children, channelDetail, onSuccess, - userSetting + userSetting, }) => { const { account, chainId, provider, wallet } = useAccount(); @@ -64,7 +66,7 @@ const UnsubscribeChannelDropdown: FC = ({ { userPushSDKInstance: sdkInstance, channelAddress: convertAddressToAddrCaip(channelAddress, chainId), - settings: notifUserSettingFormatString({ settings: settings }) + settings: notifUserSettingFormatString({ settings: settings }), }, { onSuccess: (response) => { @@ -74,7 +76,12 @@ const UnsubscribeChannelDropdown: FC = ({ toastTitle: 'Success', toastMessage: 'Successfully saved the user settings!', toastType: 'SUCCESS', - getToastIcon: (size) => + getToastIcon: (size) => ( + + ), }); } else { console.log('Error in Saving notification settings', response); @@ -82,13 +89,18 @@ const UnsubscribeChannelDropdown: FC = ({ toastTitle: 'Error', toastMessage: `There was an error in saving the settings`, toastType: 'ERROR', - getToastIcon: (size) => + getToastIcon: (size) => ( + + ), }); } }, onError: (error) => { console.log('Error in saving notification settings', error); - } + }, } ); }; @@ -105,7 +117,7 @@ const UnsubscribeChannelDropdown: FC = ({ signer: _signer, channelAddress: convertAddressToAddrCaip(channelAddress, chainId), userAddress: convertAddressToAddrCaip(account, chainId), - env: appConfig.pushNodesEnv + env: appConfig.pushNodesEnv, }, { onSuccess: (response) => { @@ -115,20 +127,30 @@ const UnsubscribeChannelDropdown: FC = ({ toastTitle: 'Success', toastMessage: 'Successfully opted out of channel !', toastType: 'SUCCESS', - getToastIcon: (size) => + getToastIcon: (size) => ( + + ), }); } else { unsubscribeToast.showMessageToast({ toastTitle: 'Error', toastMessage: `There was an error opting out of channel`, toastType: 'ERROR', - getToastIcon: (size) => + getToastIcon: (size) => ( + + ), }); } }, onError: (error) => { console.log('Error in the unsubcribe channel', error); - } + }, } ); }; @@ -153,7 +175,11 @@ const UnsubscribeChannelDropdown: FC = ({ - } onClick={handleOptOut} /> + } + onClick={handleOptOut} + /> } > diff --git a/src/common/components/index.ts b/src/common/components/index.ts index fd0249d4e7..2e2904520a 100644 --- a/src/common/components/index.ts +++ b/src/common/components/index.ts @@ -1,3 +1,7 @@ export * from './ContentLayout'; +export * from './Stepper'; export * from './SubscribeChannelDropdown'; export * from './UnsubscribeChannelDropdown'; +export * from './ModalHeader'; +export * from './StakingVariant'; +export * from './TokenFaucet'; diff --git a/src/common/hooks/useFetchUsersChannelDetails.ts b/src/common/hooks/useFetchUsersChannelDetails.ts new file mode 100644 index 0000000000..8b7204bfc4 --- /dev/null +++ b/src/common/hooks/useFetchUsersChannelDetails.ts @@ -0,0 +1,52 @@ +import { useMemo } from 'react'; + +import { appConfig } from 'config'; + +import { aliasChainIdToChainName } from 'helpers/UtilityHelper'; +import { useAccount } from 'hooks'; + +import { ALIAS_CHAIN } from 'modules/addNewChain/AddNewChain.types'; + +import { useGetAliasInfo, useGetChannelDetails } from 'queries'; + +const CORE_CHAIN_ID = appConfig.coreContractChain; + +const useFetchChannelDetails = () => { + const { account, chainId } = useAccount(); + + const onCoreNetwork: boolean = CORE_CHAIN_ID === chainId; + + const selectedChainId = parseInt(chainId); + + const aliasChain = aliasChainIdToChainName[selectedChainId as keyof typeof aliasChainIdToChainName] as ALIAS_CHAIN; + + const { data: aliasData } = useGetAliasInfo({ + alias: account, + aliasChain: aliasChain as ALIAS_CHAIN + }); + + const accountToFetchChannelDetails = useMemo(() => { + if (!onCoreNetwork && aliasData && aliasData?.channel) { + return aliasData.channel; + } + return account; + }, [onCoreNetwork, aliasData, account]); + + // Refetch interval is set based on alias is verified or not. + // 5000 is given for the case when the user is not on core network and has alias details + const refetchInterval = useMemo(() => { + if (!!(!onCoreNetwork && aliasData && aliasData?.channel)) { + return 5000; + } + return 0; + }, [onCoreNetwork, aliasData]); + + const { + data: channelDetails, + isLoading: loadingChannelDetails, + refetch: refetchChannelDetails + } = useGetChannelDetails(accountToFetchChannelDetails, refetchInterval); + + return { channelDetails, loadingChannelDetails, refetchChannelDetails }; +}; +export default useFetchChannelDetails; diff --git a/src/common/index.ts b/src/common/index.ts index 2c2603cce5..43949e8236 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -1,3 +1,5 @@ export * from './hooks'; export * from './components'; export * from './Common.constants'; +export * from './Common.utils'; +export * from './Common.form'; diff --git a/src/components/MobileNavButton.jsx b/src/components/MobileNavButton.jsx index 20403bbabb..65119166a8 100644 --- a/src/components/MobileNavButton.jsx +++ b/src/components/MobileNavButton.jsx @@ -31,8 +31,8 @@ function MobileNavButton({ item, data, sectionID, active, bg = 'none', showNavBa const { showMetamaskPushSnap } = useContext(AppContext); useEffect(() => { - setIcon(navigationIcons[data.src]); - setActiveIcon(navigationIcons[data.activeSrc]); + setIcon(navigationIcons[data.src] ?? data.src); + setActiveIcon(navigationIcons[data.activeSrc] ?? data.activeSrc); }, [data.src, data.activeSrc]); let SelectedIcon; @@ -123,6 +123,7 @@ function MobileNavButton({ item, data, sectionID, active, bg = 'none', showNavBa ) : ( + {!active ? ( { return state.user; }); @@ -106,7 +111,7 @@ function NotificationSettings() { const navigate = useNavigate(); const goBack = () => { - navigate('/dashboard', { replace: true }); + navigate(`${APP_PATHS.ChannelDashboard}/${account}`, { replace: true }); }; const addSetting = (newSetting: ChannelSetting) => { @@ -214,7 +219,7 @@ function NotificationSettings() { /> ), }); - + refetchChannelDetails(); // Go back to channel dashboard setTimeout(() => goBack(), 2000); } catch (err) { diff --git a/src/components/reusables/progress/ProgressBarUnit.tsx b/src/components/reusables/progress/ProgressBarUnit.tsx index d9c6483a03..7c01292af3 100644 --- a/src/components/reusables/progress/ProgressBarUnit.tsx +++ b/src/components/reusables/progress/ProgressBarUnit.tsx @@ -13,6 +13,8 @@ interface ProgressBarPropsI { color?: string; notice?: string; noticePositioning?: number; + backgroundColor?: string; + height?: string; } // Constants @@ -27,17 +29,21 @@ const ProgressBar = ({ color = GLOBALS.COLORS.PRIMARY_PINK, notice = null, noticePositioning = NOTICE_POSITIONING.BOTTOM, + backgroundColor = GLOBALS.COLORS.PLACEHOLDER_DARK_GRAY, + height = '10px', }: ProgressBarPropsI) => { const theme = useTheme(); return ( {notice && ( @@ -48,9 +54,8 @@ const ProgressBar = ({ textTransform="none" textAlign="center" letterSpacing="normal" - margin={`${noticePositioning == NOTICE_POSITIONING.BOTTOM ? '5px' : 0} 0 ${ - noticePositioning == NOTICE_POSITIONING.TOP ? '5px' : 0 - } 0`} + margin={`${noticePositioning == NOTICE_POSITIONING.BOTTOM ? '5px' : 0} 0 ${noticePositioning == NOTICE_POSITIONING.TOP ? '5px' : 0 + } 0`} > {notice} @@ -61,9 +66,9 @@ const ProgressBar = ({ export default ProgressBar; const Progress = styled.div` - background: ${GLOBALS.COLORS.PLACEHOLDER_DARK_GRAY}; + background: ${(props) => props.backgroundColor ? props.backgroundColor : GLOBALS.COLORS.PLACEHOLDER_DARK_GRAY}; border-radius: 18px; - height: 8px; + height: inherit; overflow: hidden; width: 100%; position: relative; diff --git a/src/config/AppPaths.ts b/src/config/AppPaths.ts index f65a85010c..471ee4ee21 100644 --- a/src/config/AppPaths.ts +++ b/src/config/AppPaths.ts @@ -6,7 +6,10 @@ enum APP_PATHS { Chat = '/chat', Spaces = '/spaces', Channels = '/channels', + ChannelDashboard = '/channel', + CreateChannel = '/channel/create', Dashboard = '/dashboard', + AddNewChain = '/add-new-chain', DiscordVerification = '/discord/verification', Rewards = '/points', RewardsActivities = '/points/activity', diff --git a/src/config/NavigationList.js b/src/config/NavigationList.js index 6f633689a5..7f78444675 100644 --- a/src/config/NavigationList.js +++ b/src/config/NavigationList.js @@ -132,7 +132,7 @@ const NavigationList = { name: 'Create Channel', title: 'Create Channel', alt: 'Create Channels / Dashboard', - href: APP_PATHS.Dashboard, + href: APP_PATHS.CreateChannel, newTab: false, isRoute: true, hasMenuLogic: true, diff --git a/src/helpers/PushTokenContractHelper.ts b/src/helpers/PushTokenContractHelper.ts index 37112dad25..649eb48c6d 100644 --- a/src/helpers/PushTokenContractHelper.ts +++ b/src/helpers/PushTokenContractHelper.ts @@ -11,7 +11,7 @@ type PushTokenApprovalAmountType = { export const getPushTokenApprovalAmount = async ({ address, provider, - contractAddress, + contractAddress }: PushTokenApprovalAmountType): Promise => { try { const pushTokenContract = new ethers.Contract(addresses.pushToken, abis.pushToken, provider); @@ -32,7 +32,7 @@ type HasEnoughPushToken = { export const getHasEnoughPushToken = async ({ address, provider, - noOfPushTokensToCheck, + noOfPushTokensToCheck }: HasEnoughPushToken): Promise => { try { const pushTokenContract = new ethers.Contract(addresses.pushToken, abis.pushToken, provider); @@ -82,25 +82,22 @@ export const approvePushToken = async ({ signer, contractAddress, amount }: Push } }; -type ImportPushTokenType = { - provider: any; -}; -export const importPushToken = async ({ provider }: ImportPushTokenType): Promise => { +export const importPushToken = async (): Promise => { try { const name = 'Ethereum Push Notification Service'; const symbol = 'PUSH'; const decimals = 18; - await provider.request({ + await window.ethereum.request({ method: 'wallet_watchAsset', params: { type: 'ERC20', options: { address: addresses.pushToken, symbol: symbol, - decimals: decimals, - }, - }, + decimals: decimals + } + } }); return true; } catch (err) { @@ -119,7 +116,7 @@ export const mintPushToken = async ({ noOfTokens, provider, account }: MintPushT var signer = provider.getSigner(account); let pushTokenContract = new ethers.Contract(addresses.pushToken, abis.pushToken, signer); console.info({ - pushTokenContract, + pushTokenContract }); console.info(1); let pushTokenAmount = noOfTokens; @@ -136,5 +133,6 @@ export const mintPushToken = async ({ noOfTokens, provider, account }: MintPushT return noOfTokens; } catch (err) { console.error(err); + return 0; } }; diff --git a/src/index.css b/src/index.css index d7685d3855..85bbe40328 100644 --- a/src/index.css +++ b/src/index.css @@ -9,8 +9,10 @@ */ html { - line-height: 1.15; /* 1 */ - -webkit-text-size-adjust: 100%; /* 2 */ + line-height: 1.15; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ } /* Sections @@ -51,9 +53,12 @@ h1 { */ hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ + box-sizing: content-box; + /* 1 */ + height: 0; + /* 1 */ + overflow: visible; + /* 2 */ } /** @@ -62,8 +67,10 @@ hr { */ pre { - font-family: FK Grotesk Neu, monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ + font-family: FK Grotesk Neu, monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } /* Text-level semantics @@ -83,9 +90,12 @@ a { */ abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ + border-bottom: none; + /* 1 */ + text-decoration: underline; + /* 2 */ + text-decoration: underline dotted; + /* 2 */ } /** @@ -105,8 +115,10 @@ strong { code, kbd, samp { - font-family: FK Grotesk Neu, monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ + font-family: FK Grotesk Neu, monospace, monospace; + /* 1 */ + font-size: 1em; + /* 2 */ } /** @@ -162,10 +174,14 @@ input, optgroup, select, textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: 1.15; + /* 1 */ + margin: 0; + /* 2 */ } /** @@ -174,7 +190,8 @@ textarea { */ button, -input { /* 1 */ +input { + /* 1 */ overflow: visible; } @@ -184,7 +201,8 @@ input { /* 1 */ */ button, -select { /* 1 */ +select { + /* 1 */ text-transform: none; } @@ -238,12 +256,18 @@ fieldset { */ legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ + box-sizing: border-box; + /* 1 */ + color: inherit; + /* 2 */ + display: table; + /* 1 */ + max-width: 100%; + /* 1 */ + padding: 0; + /* 3 */ + white-space: normal; + /* 1 */ } /** @@ -269,8 +293,10 @@ textarea { [type="checkbox"], [type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ + box-sizing: border-box; + /* 1 */ + padding: 0; + /* 2 */ } /** @@ -288,8 +314,10 @@ textarea { */ [type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ } /** @@ -306,8 +334,10 @@ textarea { */ ::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ } /* Interactive @@ -355,49 +385,49 @@ template { .Toastify { z-index: 999999; } -.Toastify__toast { - -} -.Toastify__toast--rtl { -} -.Toastify__toast--dark { -} -.Toastify__toast--default { -} -.Toastify__toast--info { -} -.Toastify__toast--success { -} -.Toastify__toast--warning { -} -.Toastify__toast--error { -} + +.Toastify__toast {} + +.Toastify__toast--rtl {} + +.Toastify__toast--dark {} + +.Toastify__toast--default {} + +.Toastify__toast--info {} + +.Toastify__toast--success {} + +.Toastify__toast--warning {} + +.Toastify__toast--error {} + .Toastify__toast-body { font-size: 12px; line-height: 1.5em; } /** Classes for the close button. Better use your own closeButton **/ -.Toastify__close-button { -} -.Toastify__close-button--default { -} -.Toastify__close-button > svg { -} -.Toastify__close-button:hover, .Toastify__close-button:focus { -} +.Toastify__close-button {} + +.Toastify__close-button--default {} + +.Toastify__close-button>svg {} + +.Toastify__close-button:hover, +.Toastify__close-button:focus {} /** Classes for the progress bar **/ -.Toastify__progress-bar { -} -.Toastify__progress-bar--animated { -} -.Toastify__progress-bar--controlled { -} -.Toastify__progress-bar--rtl { -} -.Toastify__progress-bar--default { -} +.Toastify__progress-bar {} + +.Toastify__progress-bar--animated {} + +.Toastify__progress-bar--controlled {} + +.Toastify__progress-bar--rtl {} + +.Toastify__progress-bar--default {} + .Toastify__progress-bar--dark { background: #e1087f !important; } @@ -405,10 +435,10 @@ template { /** * Custom CSS */ - @font-face { +@font-face { font-family: 'FK Grotesk Neu'; src: url('./assets/fonts/FKGroteskNeue-Regular.woff2') format('woff2'), - url('./assets/fonts/FKGroteskNeue-Regular.woff') format('woff'); + url('./assets/fonts/FKGroteskNeue-Regular.woff') format('woff'); font-weight: 100 400; font-style: normal; } @@ -417,28 +447,34 @@ template { @font-face { font-family: 'FK Grotesk Neu'; src: url('./assets/fonts/FKGroteskNeue-Medium.woff2') format('woff2'), - url('./assets/fonts/FKGroteskNeu-Medium.woff') format('woff'); + url('./assets/fonts/FKGroteskNeu-Medium.woff') format('woff'); font-weight: 500 600; font-style: normal; - -} + +} @font-face { font-family: 'FK Grotesk Neu'; src: url('./assets/fonts/FKGroteskNeue-Bold.woff2') format('woff2'), - url('./assets/fonts/FKGroteskNeue-Bold.woff') format('woff'); - font-weight: 700 800; + url('./assets/fonts/FKGroteskNeue-Bold.woff') format('woff'); + font-weight: 700 800; font-style: normal; font-display: swap; } - span, p, label, div { +span, +p, +label, +div { font-family: "FK Grotesk Neu", Helvetica, sans-serif; } -button, a, a:before, a:after { +button, +a, +a:before, +a:after { font-family: "FK Grotesk Neu", Helvetica, sans-serif; border: 0; outline: 0; @@ -450,31 +486,36 @@ button, a, a:before, a:after { } - h1 { +h1 { font-family: "FK Grotesk Neu", Helvetica, sans-serif; - font-weight: 700; - line-height: 1.25em; - color: #fff; - text-transform: uppercase; - font-size: 2.25rem; - text-shadow: 0 0 20px rgb(255 255 255 / 60%); - letter-spacing: normal; - } - - h2, h3, h4, h5, h6 { - font-family: 'FK Grotesk Neu', Helvetica, sans-serif; - font-weight: 500; - font-size: 32px; - line-height: 1.25em; - line-height: 1.25em; - } + font-weight: 700; + line-height: 1.25em; + color: #fff; + text-transform: uppercase; + font-size: 2.25rem; + text-shadow: 0 0 20px rgb(255 255 255 / 60%); + letter-spacing: normal; +} + +h2, +h3, +h4, +h5, +h6 { + font-family: 'FK Grotesk Neu', Helvetica, sans-serif; + font-weight: 500; + font-size: 32px; + line-height: 1.25em; + line-height: 1.25em; +} /* * VIDEO WRAPPER */ - .videoWrapper { +.videoWrapper { position: relative; - padding-bottom: 56.25%; /* 16:9 */ + padding-bottom: 56.25%; + /* 16:9 */ height: 0; width: 100%; } @@ -492,38 +533,39 @@ button, a, a:before, a:after { */ /* Secondary */ #scrollstyle-secondary::-webkit-scrollbar-track { - background-color: #EEE; - border-radius: 10px; + background-color: #EEE; + border-radius: 10px; } #scrollstyle-secondary::-webkit-scrollbar { - width: 6px; - background-color: #EEE; + width: 6px; + background-color: #EEE; } #scrollstyle-secondary::-webkit-scrollbar-thumb { - border-radius: 10px; - background-image: -webkit-gradient(linear, - left top, - left bottom, - color-stop(0.44, #35c5f3), - color-stop(0.72, #35b0f3), - color-stop(0.86, #35a1f3)); + border-radius: 10px; + background-image: -webkit-gradient(linear, + left top, + left bottom, + color-stop(0.44, #35c5f3), + color-stop(0.72, #35b0f3), + color-stop(0.86, #35a1f3)); } /* style modification for react select */ -.select__control{ +.select__control { height: 100% !important; border-radius: 0 !important; border: 1px solid black !important; box-shadow: unset !important; } -.select__control:hover{ + +.select__control:hover { border-color: black !important; } -.basic-single{ +.basic-single { position: absolute !important; width: 20% !important; min-width: 200px !important; @@ -542,8 +584,8 @@ button, a, a:before, a:after { --w3o-action-color: #C631C6 !important; --w3o-border-radius: 24px !important; --w3o-font-family: unset !important; - --onboard-modal-backdrop: transparent !important; - --onboard-modal-z-index:999999 !important; + /* --onboard-modal-backdrop: transparent !important; */ + --onboard-modal-z-index: 999999 !important; --modal-backdrop: transparent !important; /* Wallet connect modal z-index */ @@ -560,21 +602,20 @@ button, a, a:before, a:after { --w3o-border-radius: 24px !important; --w3o-font-family: unset !important; --onboard-modal-backdrop: transparent !important; - --onboard-modal-z-index:999999 !important; + --onboard-modal-z-index: 999999 !important; --modal-backdrop: transparent !important; } #onboard-container { - position: absolute; + position: absolute; top: 14rem; margin: auto; - background-color: transparent; + background-color: transparent; left: 20px; - right: 20px; - margin-left: auto; + right: 20px; + margin-left: auto; margin-right: auto; border-radius: var(--w3o-border-radius); overflow: auto; - z-index: 9999999; -} - + z-index: 9999999; +} \ No newline at end of file diff --git a/src/modules/addNewChain/AddNewChain.constants.tsx b/src/modules/addNewChain/AddNewChain.constants.tsx new file mode 100644 index 0000000000..f96031cb6d --- /dev/null +++ b/src/modules/addNewChain/AddNewChain.constants.tsx @@ -0,0 +1,11 @@ +import { AddNewChainStepsType } from './AddNewChain.types'; +import { appConfig } from 'config'; + +export const addNewChainSteps: AddNewChainStepsType = [ + { label: 'New Address', value: 'newaddress' }, + { label: 'Change Network', value: 'changenetwork' }, + { label: 'Verify Alias Chain', value: 'verifyalias' }, +]; +export const allowedNetworks = appConfig.allowedNetworks.filter( + (chain: number) => chain != appConfig.coreContractChain +); diff --git a/src/modules/addNewChain/AddNewChain.form.tsx b/src/modules/addNewChain/AddNewChain.form.tsx new file mode 100644 index 0000000000..6721fbdfa6 --- /dev/null +++ b/src/modules/addNewChain/AddNewChain.form.tsx @@ -0,0 +1,46 @@ +import React, { FC } from 'react'; +import { FormikProvider, useFormik, useFormikContext } from 'formik'; +import * as yup from 'yup'; + +import { isValidAddress } from 'helpers/ValidationHelper'; +import { allowedNetworks } from './AddNewChain.constants'; + +export type NewChainAddressValue = { + alias: string; + chainId: string; +}; + +type FormikChainAliasProviderProps = { + children: React.ReactNode; + onSubmit: (values: NewChainAddressValue) => void; +}; +const validationSchema = yup.object().shape({ + alias: yup + .string() + .required('Address is required') + .test('is-valid-address', 'Invalid wallet address', isValidAddress), + chainId: yup.string().required('ChainId is required'), +}); + +const FormikChainAliasProvider: FC = ({ children, onSubmit }) => { + const formik = useFormik({ + initialValues: { + alias: '', + chainId: allowedNetworks[0].toString(), + }, + validationSchema: validationSchema, + onSubmit: onSubmit, + }); + + return {children}; +}; + +const useChainAliasForm = () => { + const context = useFormikContext(); + if (!context) { + throw new Error('useChainAliasFormikContext must be used within a FormikChainAliasProvider'); + } + return context; +}; + +export { FormikChainAliasProvider, useChainAliasForm }; diff --git a/src/modules/addNewChain/AddNewChain.tsx b/src/modules/addNewChain/AddNewChain.tsx new file mode 100644 index 0000000000..9574a7ea1c --- /dev/null +++ b/src/modules/addNewChain/AddNewChain.tsx @@ -0,0 +1,227 @@ +// React and other libraries +import { FC, useEffect, useState } from 'react'; + +import { useSelector } from 'react-redux'; +import { css } from 'styled-components'; +import { MdError } from 'react-icons/md'; +import { useNavigate } from 'react-router-dom'; + +import useToast from 'hooks/useToast'; +import { useGetAliasInfo, useGetChannelDetails, useInitiateNewChain } from 'queries'; +import { useAccount } from 'hooks'; + +import { addNewChainSteps } from './AddNewChain.constants'; +import APP_PATHS from 'config/AppPaths'; +import { appConfig } from 'config'; + +import { NewAddress } from './components/NewAddress'; +import { ChangeNetwork } from './components/ChangeNetwork'; +import { VerifyAliasChain } from './components/VerifyAliasChain'; +import UnlockProfileWrapper, { UNLOCK_PROFILE_TYPE } from 'components/chat/unlockProfile/UnlockProfileWrapper'; +import { Alert, Box, Button, Text } from 'blocks'; +import { Stepper } from 'common'; + +import { UserStoreType } from 'types'; +import { ALIAS_CHAIN, ActiveStepKey } from './AddNewChain.types'; + +import { aliasChainIdToChainName } from 'helpers/UtilityHelper'; +import { convertAddressToAddrCaip } from 'helpers/CaipHelper'; + +import { FormikChainAliasProvider } from './AddNewChain.form'; + +const AddNewChain: FC = () => { + const [activeStepKey, setActiveStepKey] = useState('newaddress'); + const [completedSteps, setCompletedSteps] = useState>(['newaddress']); + const [isAuthModalVisible, setIsAuthModalVisible] = useState(true); + + const toast = useToast(); + const { mutate: initiateNewChain, isPending, isError } = useInitiateNewChain(); + const { userPushSDKInstance } = useSelector((state: UserStoreType) => state.user); + const { account, chainId, switchChain } = useAccount(); + const { data: channelDetails } = useGetChannelDetails(account); + const { data: alaisDetails } = useGetAliasInfo({ + alias: account, + aliasChain: aliasChainIdToChainName[chainId as keyof typeof aliasChainIdToChainName] as ALIAS_CHAIN, + }); + + const navigate = useNavigate(); + + useEffect(() => { + setIsAuthModalVisible(userPushSDKInstance && userPushSDKInstance?.readmode()); + }, [userPushSDKInstance]); + + const handleInitiate = (alias: string, chainId: string) => { + setCompletedSteps(['newaddress']); + initiateNewChain( + { + userPushSDKInstance, + alias: convertAddressToAddrCaip(alias, parseInt(chainId)), + }, + { + onSuccess: () => { + handleNextStep('changenetwork'); + }, + onError: (error: any) => { + if (error) { + toast.showMessageToast({ + toastTitle: 'Error', + toastMessage: error.message, + toastType: 'ERROR', + getToastIcon: (size) => ( + + ), + }); + } + }, + } + ); + }; + + const handleNextStep = (key: ActiveStepKey) => { + setCompletedSteps([...new Set([...completedSteps, key])]); + setActiveStepKey(key); + }; + + const handleCloseAuthModal = () => { + if (channelDetails) navigate(`${APP_PATHS.ChannelDashboard}/${account}}`); + else navigate(APP_PATHS.WelcomeDashboard); + setIsAuthModalVisible(false); + }; + + return ( + handleInitiate(values.alias, values.chainId)}> + + + + + Add New Chain to Channel + + + Add New Chain to Channel + + + Add an alias chain to your channel to enable notifications to that chain. + + + Add an alias chain to your channel to enable notifications to that chain. + + + {chainId !== appConfig.coreContractChain && completedSteps.length === 1 ? ( + <> + + + Please change your network to Ethereum to proceed. + + + + + ) : channelDetails || alaisDetails ? ( + <> + setActiveStepKey(key as ActiveStepKey)} + /> + {activeStepKey === 'newaddress' && ( + + )} + {activeStepKey === 'changenetwork' && } + {activeStepKey === 'verifyalias' && } + + ) : ( + <> + + + + )} + {isAuthModalVisible && ( + + + + )} + + + Tip: Please do not exit the process before the address is verified. If you leave, you will need to start over. + + + + ); +}; + +export { AddNewChain }; diff --git a/src/modules/addNewChain/AddNewChain.types.tsx b/src/modules/addNewChain/AddNewChain.types.tsx new file mode 100644 index 0000000000..dd953fb98c --- /dev/null +++ b/src/modules/addNewChain/AddNewChain.types.tsx @@ -0,0 +1,13 @@ +export type ActiveStepKey = 'newaddress' | 'changenetwork' | 'verifyalias'; +export type AddNewChainStepsType = Array<{ label: string; value: ActiveStepKey }>; +export type ALIAS_CHAIN = + | 'POLYGON' + | 'BSC' + | 'OPTIMISM' + | 'POLYGONZKEVM' + | 'ARBITRUMONE' + | 'FUSE' + | 'BERACHAIN' + | 'LINEA' + | 'CYBERCONNECT' + | 'BASE'; diff --git a/src/modules/addNewChain/AddNewChain.utils.tsx b/src/modules/addNewChain/AddNewChain.utils.tsx new file mode 100644 index 0000000000..378abbc3e5 --- /dev/null +++ b/src/modules/addNewChain/AddNewChain.utils.tsx @@ -0,0 +1,14 @@ +import { LOGO_ALIAS_CHAIN } from 'common'; +import { appConfig } from 'config'; +import { networkName } from 'helpers/UtilityHelper'; + +export const getSelectChains = () => { + return appConfig.allowedNetworks.map((key: number) => { + const Component = LOGO_ALIAS_CHAIN[key]; + return { + value: key.toString(), + label: networkName[key as keyof typeof networkName], + icon: , + }; + }); +}; diff --git a/src/modules/addNewChain/components/ChangeNetwork.tsx b/src/modules/addNewChain/components/ChangeNetwork.tsx new file mode 100644 index 0000000000..1c52d17455 --- /dev/null +++ b/src/modules/addNewChain/components/ChangeNetwork.tsx @@ -0,0 +1,42 @@ +import { FC, useEffect } from 'react'; + +import { useAccount } from 'hooks'; + +import { Box, Button, Text } from 'blocks'; +import { ActiveStepKey } from '../AddNewChain.types'; + +import { useChainAliasForm } from '../AddNewChain.form'; + +export type ChangeNetworkProps = { + handleNextStep: (key: ActiveStepKey) => void; +}; + +const ChangeNetwork: FC = ({ handleNextStep }) => { + const { switchChain, chainId } = useAccount(); + const { values: formValues } = useChainAliasForm(); + const selectedChainId = parseInt(formValues.chainId); + useEffect(() => { + if (chainId === selectedChainId) { + handleNextStep('verifyalias'); + } + }, [chainId]); + + return ( + + + Switch to the desired chain in your wallet to add it to your channel. + + + + ); +}; + +export { ChangeNetwork }; diff --git a/src/modules/addNewChain/components/NewAddress.tsx b/src/modules/addNewChain/components/NewAddress.tsx new file mode 100644 index 0000000000..58314d1792 --- /dev/null +++ b/src/modules/addNewChain/components/NewAddress.tsx @@ -0,0 +1,97 @@ +import { FC } from 'react'; + +import { Alert, Box, Button, Select, TextInput } from 'blocks'; + +import { getSelectChains } from 'common'; + +import { useChainAliasForm } from '../AddNewChain.form'; + +import { allowedNetworks } from '../AddNewChain.constants'; + +import { ChannelDetails } from 'queries'; + +export type NewAddressProps = { + isLoading: boolean; + channelDetails: ChannelDetails | undefined; +}; + +const NewAddress: FC = ({ isLoading, channelDetails }) => { + const selectChainOptions = getSelectChains(allowedNetworks); + const { values: formValues, handleSubmit, handleChange, errors, touched } = useChainAliasForm(); + const isAliasNetworkExists = channelDetails?.aliases.find( + (alias) => alias.alias_blockchain_id === formValues.chainId && alias.is_alias_verified + ); + + const validateInput = () => { + if (!isAliasNetworkExists && formValues.alias) return false; + return true; + }; + + return ( + + {isAliasNetworkExists && ( + + )} +
+ + + + + + +