diff --git a/build-webapp.sh b/build-webapp.sh
index e6476e6f..b289f28f 100755
--- a/build-webapp.sh
+++ b/build-webapp.sh
@@ -17,6 +17,7 @@ VITE_GITHUB_IMAGE_UPLOAD_PWA_TEMPLATE_REPO = 'LACONIC_HOSTED_CONFIG_github_image
VITE_GITHUB_NEXT_APP_TEMPLATE_REPO = 'LACONIC_HOSTED_CONFIG_github_next_app_templaterepo'
VITE_WALLET_CONNECT_ID = 'LACONIC_HOSTED_CONFIG_wallet_connect_id'
VITE_LACONICD_CHAIN_ID = 'LACONIC_HOSTED_CONFIG_laconicd_chain_id'
+VITE_WALLET_IFRAME_URL = 'LACONIC_HOSTED_CONFIG_wallet_iframe_url'
VITE_LIT_RELAY_API_KEY = 'LACONIC_HOSTED_CONFIG_lit_relay_api_key'
VITE_BUGSNAG_API_KEY = 'LACONIC_HOSTED_CONFIG_bugsnag_api_key'
VITE_PASSKEY_WALLET_RPID = 'LACONIC_HOSTED_CONFIG_passkey_wallet_rpid'
diff --git a/packages/deployer/.gitignore b/packages/deployer/.gitignore
new file mode 100644
index 00000000..ffaf3b27
--- /dev/null
+++ b/packages/deployer/.gitignore
@@ -0,0 +1,2 @@
+records/*
+staging-records/*
diff --git a/packages/deployer/deploy-frontend.sh b/packages/deployer/deploy-frontend.sh
index 6365ada2..edbafa6d 100755
--- a/packages/deployer/deploy-frontend.sh
+++ b/packages/deployer/deploy-frontend.sh
@@ -135,6 +135,7 @@ record:
LACONIC_HOSTED_CONFIG_github_next_app_templaterepo: laconic-templates/starter.nextjs-react-tailwind
LACONIC_HOSTED_CONFIG_wallet_connect_id: 63cad7ba97391f63652161f484670e15
LACONIC_HOSTED_CONFIG_laconicd_chain_id: laconic-testnet-2
+ LACONIC_HOSTED_CONFIG_wallet_iframe_url: https://wallet.laconic.com
meta:
note: Added @ $CURRENT_DATE_TIME
repository: "$REPO_URL"
diff --git a/packages/deployer/records/application-deployment-request.yml b/packages/deployer/records/application-deployment-request.yml
deleted file mode 100644
index 2b53d579..00000000
--- a/packages/deployer/records/application-deployment-request.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-record:
- type: ApplicationDeploymentRequest
- version: '1.0.0'
- name: deploy-frontend@1.0.0
- application: lrn://vaasl/applications/deploy-frontend@1.0.0
- dns: deploy
- config:
- env:
- LACONIC_HOSTED_CONFIG_server_url: https://deploy-backend.apps.vaasl.io
- LACONIC_HOSTED_CONFIG_github_clientid: Ov23liaet4yc0KX0iM1c
- LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: laconic-templates/test-progressive-web-app
- LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: laconic-templates/image-upload-pwa-example
- LACONIC_HOSTED_CONFIG_github_next_app_templaterepo: laconic-templates/starter.nextjs-react-tailwind
- LACONIC_HOSTED_CONFIG_wallet_connect_id: 63cad7ba97391f63652161f484670e15
- meta:
- note: Added by Snowball @ Thu Apr 4 14:49:41 UTC 2024
- repository: "https://git.vdb.to/cerc-io/snowballtools-base"
- repository_ref: 351db16336eacc3e1f9119ceb8d1282b8e27a27e
diff --git a/packages/deployer/records/application-record.yml b/packages/deployer/records/application-record.yml
deleted file mode 100644
index 9e23075f..00000000
--- a/packages/deployer/records/application-record.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-record:
- type: ApplicationRecord
- version: 0.0.2
- repository_ref: 351db16336eacc3e1f9119ceb8d1282b8e27a27e
- repository: ["https://git.vdb.to/cerc-io/snowballtools-base"]
- app_type: webapp
- name: deploy-frontend
- app_version: 1.0.0
diff --git a/packages/deployer/staging-records/application-deployment-request.yml b/packages/deployer/staging-records/application-deployment-request.yml
deleted file mode 100644
index fd7ee288..00000000
--- a/packages/deployer/staging-records/application-deployment-request.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-record:
- type: ApplicationDeploymentRequest
- version: '1.0.0'
- name: staging-snowballtools-base-frontend@0.0.0
- application: crn://staging-snowballtools/applications/staging-snowballtools-base-frontend@0.0.0
- dns: dashboard.staging.apps.snowballtools.com
- config:
- env:
- LACONIC_HOSTED_CONFIG_server_url: https://snowballtools-base-api.staging.apps.snowballtools.com
- LACONIC_HOSTED_CONFIG_github_clientid: Ov23liOaoahRTYd4nSCV
- LACONIC_HOSTED_CONFIG_github_templaterepo: snowball-tools/test-progressive-web-app
- LACONIC_HOSTED_CONFIG_github_pwa_templaterepo: snowball-tools/test-progressive-web-app
- LACONIC_HOSTED_CONFIG_github_image_upload_templaterepo: snowball-tools/image-upload-pwa-example
- LACONIC_HOSTED_CONFIG_github_next_app_templaterepo: snowball-tools/starter.nextjs-react-tailwind
- LACONIC_HOSTED_CONFIG_wallet_connect_id: eda9ba18042a5ea500f358194611ece2
- LACONIC_HOSTED_CONFIG_lit_relay_api_key: 15DDD969-E75F-404D-AAD9-58A37C4FD354_snowball
- LACONIC_HOSTED_CONFIG_aplchemy_api_key: THvPart_gqI5x02RNYSBntlmwA66I_qc
- LACONIC_HOSTED_CONFIG_bugsnag_api_key: 8c480cd5386079f9dd44f9581264a073
- LACONIC_HOSTED_CONFIG_passkey_wallet_rpid: dashboard.staging.apps.snowballtools.com
- LACONIC_HOSTED_CONFIG_turnkey_api_base_url: https://api.turnkey.com
- LACONIC_HOSTED_CONFIG_turnkey_organization_id: 5049ae99-5bca-40b3-8317-504384d4e591
- meta:
- note: Added by Snowball @ Mon Jun 24 23:51:48 UTC 2024
- repository: "https://git.vdb.to/cerc-io/snowballtools-base"
- repository_ref: 61e3e88a6c9d57e95441059369ee5a46f5c07601
diff --git a/packages/deployer/staging-records/application-record.yml b/packages/deployer/staging-records/application-record.yml
deleted file mode 100644
index fa9b4089..00000000
--- a/packages/deployer/staging-records/application-record.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-record:
- type: ApplicationRecord
- version: 0.0.1
- repository_ref: 61e3e88a6c9d57e95441059369ee5a46f5c07601
- repository: ["https://git.vdb.to/cerc-io/snowballtools-base"]
- app_type: webapp
- name: staging-snowballtools-base-frontend
- app_version: 0.0.0
diff --git a/packages/frontend/.env.example b/packages/frontend/.env.example
index 88f6bc1f..62241552 100644
--- a/packages/frontend/.env.example
+++ b/packages/frontend/.env.example
@@ -15,3 +15,4 @@ VITE_PASSKEY_WALLET_RPID=
VITE_TURNKEY_API_BASE_URL=
VITE_LACONICD_CHAIN_ID=
+VITE_WALLET_IFRAME_URL=
diff --git a/packages/frontend/src/components/projects/Dialog/ChangeStateToProductionDialog.tsx b/packages/frontend/src/components/projects/Dialog/ChangeStateToProductionDialog.tsx
index efb9c2fa..be68a445 100644
--- a/packages/frontend/src/components/projects/Dialog/ChangeStateToProductionDialog.tsx
+++ b/packages/frontend/src/components/projects/Dialog/ChangeStateToProductionDialog.tsx
@@ -47,6 +47,11 @@ export const ChangeStateToProductionDialog = ({
handleCancel={handleCancel}
open={open}
handleConfirm={handleConfirm}
+ confirmButtonTitle={
+ isConfirmButtonLoading
+ ? 'Redeploying'
+ : 'Redeploy'
+ }
confirmButtonProps={{
disabled: isConfirmButtonLoading,
rightIcon: isConfirmButtonLoading ? (
diff --git a/packages/frontend/src/components/projects/create/AccountsDropdown.tsx b/packages/frontend/src/components/projects/create/AccountsDropdown.tsx
new file mode 100644
index 00000000..4ef0a61f
--- /dev/null
+++ b/packages/frontend/src/components/projects/create/AccountsDropdown.tsx
@@ -0,0 +1,60 @@
+import {
+ Select,
+ Option,
+ Spinner,
+} from '@snowballtools/material-tailwind-react-fork';
+
+const AccountsDropdown = ({
+ accounts,
+ isDataReceived,
+ onAccountChange,
+}: {
+ accounts: string[];
+ isDataReceived: boolean;
+ onAccountChange: (selectedAccount: string) => void;
+}) => {
+ return (
+
+ {isDataReceived ? (
+ !accounts.length ? (
+
+ ) : (
+
+ value && onAccountChange(value)}
+ className="dark:bg-overlay2 dark:text-foreground"
+ aria-label="Wallet Account Selector"
+ >
+ {accounts.map((account, index) => (
+
+ {account}
+
+ ))}
+
+
+ )
+ ) : (
+
+
+
+ )}
+
+ );
+};
+
+export default AccountsDropdown;
diff --git a/packages/frontend/src/components/projects/create/Configure.tsx b/packages/frontend/src/components/projects/create/Configure.tsx
index 4dae836b..c541cd6d 100644
--- a/packages/frontend/src/components/projects/create/Configure.tsx
+++ b/packages/frontend/src/components/projects/create/Configure.tsx
@@ -20,10 +20,14 @@ import { Button } from '../../shared/Button';
import { Input } from 'components/shared/Input';
import { useToast } from 'components/shared/Toast';
import { useGQLClient } from '../../../context/GQLClientContext';
+import IFrameModal from './IFrameModal';
import EnvironmentVariablesForm from 'pages/org-slug/projects/id/settings/EnvironmentVariablesForm';
import { EnvironmentVariablesFormValues } from 'types/types';
-import ConnectWallet from './ConnectWallet';
-import { useWalletConnectClient } from 'context/WalletConnectContext';
+import {
+ VITE_LACONICD_CHAIN_ID,
+ VITE_WALLET_IFRAME_URL,
+} from 'utils/constants';
+import AccountsDropdown from './AccountsDropdown';
type ConfigureDeploymentFormValues = {
option: string;
@@ -36,16 +40,18 @@ type ConfigureFormValues = ConfigureDeploymentFormValues &
EnvironmentVariablesFormValues;
const DEFAULT_MAX_PRICE = '10000';
+const TX_APPROVAL_TIMEOUT_MS = 60000;
const Configure = () => {
- const { signClient, session, accounts } = useWalletConnectClient();
-
const [isLoading, setIsLoading] = useState(false);
const [deployers, setDeployers] = useState([]);
const [selectedAccount, setSelectedAccount] = useState();
+ const [accounts, setAccounts] = useState([]);
const [selectedDeployer, setSelectedDeployer] = useState();
const [isPaymentLoading, setIsPaymentLoading] = useState(false);
const [isPaymentDone, setIsPaymentDone] = useState(false);
+ const [isFrameVisible, setIsFrameVisible] = useState(false);
+ const [isAccountsDataReceived, setIsAccountsDataReceived] = useState(false);
const [searchParams] = useSearchParams();
const templateId = searchParams.get('templateId');
@@ -182,7 +188,7 @@ const Configure = () => {
let amount: string;
let senderAddress: string;
- let txHash: string;
+ let txHash: string | null = null;
if (createFormData.option === 'LRN' && !deployer?.minimumPayment) {
toast({
id: 'no-payment-required',
@@ -196,7 +202,7 @@ const Configure = () => {
} else {
if (!selectedAccount) return;
- senderAddress = selectedAccount.split(':')[2];
+ senderAddress = selectedAccount;
if (createFormData.option === 'LRN') {
amount = deployer?.minimumPayment!;
@@ -208,27 +214,40 @@ const Configure = () => {
const amountToBePaid = amount.replace(/\D/g, '').toString();
- const txHashResponse = await cosmosSendTokensHandler(
- selectedAccount,
- amountToBePaid,
- );
+ txHash = await cosmosSendTokensHandler(senderAddress, amountToBePaid);
- if (!txHashResponse) {
- console.error('Tx not successful');
- return;
+ if (!txHash) {
+ toast({
+ id: 'unsuccessful-tx',
+ title: 'Transaction rejected',
+ variant: 'error',
+ onDismiss: dismiss,
+ });
+ setIsFrameVisible(false);
+ setIsPaymentLoading(false);
+ throw new Error('Transaction rejected');
}
- txHash = txHashResponse;
+ // Validate transaction hash
+ const isTxHashValid = await verifyTx(senderAddress, txHash, amountToBePaid);
+ setIsPaymentLoading(false);
- const isTxHashValid = await verifyTx(
- senderAddress,
- txHash,
- amountToBePaid.toString(),
- );
-
- if (isTxHashValid === false) {
- console.error('Invalid Tx hash', txHash);
- return;
+ if (isTxHashValid) {
+ toast({
+ id: 'payment-successful',
+ title: 'Payment successful',
+ variant: 'success',
+ onDismiss: dismiss,
+ });
+ setIsPaymentDone(true);
+ } else {
+ toast({
+ id: 'invalid-tx-hash',
+ title: 'Transaction validation failed',
+ variant: 'error',
+ onDismiss: dismiss,
+ });
+ throw new Error('Transaction validation failed');
}
}
@@ -248,7 +267,7 @@ const Configure = () => {
createFormData,
environmentVariables,
senderAddress,
- txHash,
+ txHash!,
);
await client.getEnvironmentVariables(projectId);
@@ -270,14 +289,14 @@ const Configure = () => {
`/${orgSlug}/projects/create/deploy?projectId=${projectId}`,
);
}
- } catch (error) {
- console.error(error);
+ } catch (error: any) {
toast({
id: 'error-deploying-app',
title: 'Error deploying app',
variant: 'error',
onDismiss: dismiss,
});
+ throw new Error(error);
}
},
[client, createProject, dismiss, toast],
@@ -302,72 +321,95 @@ const Configure = () => {
const cosmosSendTokensHandler = useCallback(
async (selectedAccount: string, amount: string) => {
- if (!signClient || !session || !selectedAccount) {
- return;
+ if (!selectedAccount) {
+ throw new Error('Account not selected');
}
- const chainId = selectedAccount.split(':')[1];
- const senderAddress = selectedAccount.split(':')[2];
+ const senderAddress = selectedAccount;
const snowballAddress = await client.getAddress();
+ let timeoutId;
try {
setIsPaymentDone(false);
setIsPaymentLoading(true);
- toast({
- id: 'sending-payment-request',
- title: 'Check your wallet and approve payment request',
- variant: 'loading',
- onDismiss: dismiss,
+ await requestTx(senderAddress, snowballAddress, amount);
+
+ const txHash = await new Promise((resolve, reject) => {
+ const handleTxStatus = async (event: MessageEvent) => {
+ if (event.origin !== VITE_WALLET_IFRAME_URL) return;
+
+ if (event.data.type === 'TRANSACTION_RESPONSE') {
+ const txResponse = event.data.data;
+ resolve(txResponse);
+ } else if (event.data.type === 'ERROR') {
+ console.error('Error from wallet:', event.data.message);
+ reject(new Error('Transaction failed'));
+ toast({
+ id: 'error-transaction',
+ title: 'Error during transaction',
+ variant: 'error',
+ onDismiss: dismiss,
+ });
+ }
+ setIsFrameVisible(false);
+
+ window.removeEventListener('message', handleTxStatus);
+ };
+
+ window.addEventListener('message', handleTxStatus);
+
+ // Set a timeout, consider unsuccessful after 1 min
+ timeoutId = setTimeout(() => {
+ reject(new Error('Transaction timeout'));
+ window.removeEventListener('message', handleTxStatus);
+ toast({
+ id: 'transaction-timeout',
+ title: 'The transaction request timed out. Please try again',
+ variant: 'error',
+ onDismiss: dismiss,
+ });
+ setIsFrameVisible(false);
+ setIsPaymentLoading(false);
+ }, TX_APPROVAL_TIMEOUT_MS);
});
-
- const result: { signature: string } = await signClient.request({
- topic: session.topic,
- chainId: `cosmos:${chainId}`,
- request: {
- method: 'cosmos_sendTokens',
- params: [
- {
- from: senderAddress,
- to: snowballAddress,
- value: amount,
- },
- ],
- },
- });
-
- if (!result) {
- throw new Error('Error completing transaction');
- }
-
- toast({
- id: 'payment-successful',
- title: 'Payment successful',
- variant: 'success',
- onDismiss: dismiss,
- });
-
- setIsPaymentDone(true);
-
- return result.signature;
- } catch (error: any) {
- console.error('Error sending tokens', error);
-
- toast({
- id: 'error-sending-tokens',
- title: 'Error sending tokens',
- variant: 'error',
- onDismiss: dismiss,
- });
-
- setIsPaymentDone(false);
+ return txHash;
+ } catch (error) {
+ console.error('Error in transaction:', error);
+ throw new Error('Error in transaction');
} finally {
- setIsPaymentLoading(false);
+ clearTimeout(timeoutId);
}
},
- [session, signClient, toast],
+ [client, dismiss, toast],
);
+ const requestTx = async (
+ sender: string,
+ recipient: string,
+ amount: string,
+ ) => {
+ const iframe = document.getElementById('walletIframe') as HTMLIFrameElement;
+
+ if (!iframe.contentWindow) {
+ console.error('Iframe not found or not loaded');
+ throw new Error('Iframe not found or not loaded');
+ }
+
+ iframe.contentWindow.postMessage(
+ {
+ type: 'REQUEST_TX',
+ chainId: VITE_LACONICD_CHAIN_ID,
+ fromAddress: sender,
+ toAddress: recipient,
+ amount,
+ },
+ VITE_WALLET_IFRAME_URL,
+ );
+
+ setIsFrameVisible(true);
+ };
+
useEffect(() => {
fetchDeployers();
}, []);
@@ -534,10 +576,11 @@ const Configure = () => {
) : (
<>
-
- Connect to your wallet
-
-
+
{accounts.length > 0 && (
{
)}
+
+
);
diff --git a/packages/frontend/src/components/projects/create/ConnectWallet.tsx b/packages/frontend/src/components/projects/create/ConnectWallet.tsx
deleted file mode 100644
index 3b37fb54..00000000
--- a/packages/frontend/src/components/projects/create/ConnectWallet.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import { Select, Option } from '@snowballtools/material-tailwind-react-fork';
-
-import { Button } from '../../shared/Button';
-import { useWalletConnectClient } from 'context/WalletConnectContext';
-
-const ConnectWallet = ({
- onAccountChange,
-}: {
- onAccountChange: (selectedAccount: string) => void;
-}) => {
- const { onConnect, accounts } = useWalletConnectClient();
-
- const handleConnect = async () => {
- await onConnect();
- };
-
- return (
-
- {accounts.length === 0 ? (
-
-
- Connect Wallet
-
-
- ) : (
-
- {
- value && onAccountChange(value);
- }}
- className="dark:bg-overlay2 dark:text-foreground"
- >
- {accounts.map((account, index) => (
-
- {account.address.split(':').slice(1).join(':')}
-
- ))}
-
-
- )}
-
- );
-};
-
-export default ConnectWallet;
diff --git a/packages/frontend/src/components/projects/create/IFrameModal.tsx b/packages/frontend/src/components/projects/create/IFrameModal.tsx
new file mode 100644
index 00000000..cb4d2d82
--- /dev/null
+++ b/packages/frontend/src/components/projects/create/IFrameModal.tsx
@@ -0,0 +1,88 @@
+import { useCallback, useEffect } from 'react';
+
+import { Box, Modal } from '@mui/material';
+
+import {
+ VITE_LACONICD_CHAIN_ID,
+ VITE_WALLET_IFRAME_URL,
+} from 'utils/constants';
+
+const IFrameModal = ({
+ setAccounts,
+ setIsDataReceived,
+ isVisible,
+}: {
+ setAccounts: (accounts: string[]) => void;
+ setIsDataReceived: (isReceived: boolean) => void;
+ isVisible: boolean;
+}) => {
+ useEffect(() => {
+ const handleMessage = (event: MessageEvent) => {
+ if (event.origin !== VITE_WALLET_IFRAME_URL) return;
+
+ setIsDataReceived(true);
+ if (event.data.type === 'WALLET_ACCOUNTS_DATA') {
+ setAccounts(event.data.data);
+ } else if (event.data.type === 'ERROR') {
+ console.error('Error from wallet:', event.data.message);
+ }
+ };
+
+ window.addEventListener('message', handleMessage);
+
+ return () => {
+ window.removeEventListener('message', handleMessage);
+ };
+ }, []);
+
+ const getDataFromWallet = useCallback(() => {
+ const iframe = document.getElementById('walletIframe') as HTMLIFrameElement;
+
+ if (!iframe.contentWindow) {
+ console.error('Iframe not found or not loaded');
+ return;
+ }
+
+ iframe.contentWindow.postMessage(
+ {
+ type: 'REQUEST_WALLET_ACCOUNTS',
+ chainId: VITE_LACONICD_CHAIN_ID,
+ },
+ VITE_WALLET_IFRAME_URL,
+ );
+ }, []);
+
+ return (
+
+
+
+
+
+ );
+};
+
+export default IFrameModal;
diff --git a/packages/frontend/src/context/WalletConnectContext.tsx b/packages/frontend/src/context/WalletConnectContext.tsx
deleted file mode 100644
index e5dc4fc9..00000000
--- a/packages/frontend/src/context/WalletConnectContext.tsx
+++ /dev/null
@@ -1,210 +0,0 @@
-import {
- createContext,
- useCallback,
- useContext,
- useEffect,
- useRef,
- useState,
-} from 'react';
-
-import SignClient from '@walletconnect/sign-client';
-import { getSdkError } from '@walletconnect/utils';
-import { SessionTypes } from '@walletconnect/types';
-
-import { walletConnectModal } from '../utils/web3modal';
-import {
- VITE_LACONICD_CHAIN_ID,
- VITE_WALLET_CONNECT_ID,
-} from 'utils/constants';
-
-interface ClientInterface {
- signClient: SignClient | undefined;
- session: SessionTypes.Struct | undefined;
- loadingSession: boolean;
- onConnect: () => Promise;
- onDisconnect: () => Promise;
- onSessionDelete: () => void;
- accounts: { address: string }[];
-}
-
-const ClientContext = createContext({} as ClientInterface);
-
-export const useWalletConnectClient = () => {
- return useContext(ClientContext);
-};
-
-export const WalletConnectClientProvider = ({
- children,
-}: {
- children: JSX.Element;
-}) => {
- const [signClient, setSignClient] = useState();
- const [session, setSession] = useState();
- const [loadingSession, setLoadingSession] = useState(true);
- const [accounts, setAccounts] = useState<{ address: string }[]>([]);
-
- const isSignClientInitializing = useRef(false);
-
- const onSessionConnect = useCallback(async (session: SessionTypes.Struct) => {
- setSession(session);
- }, []);
-
- const subscribeToEvents = useCallback(
- async (client: SignClient) => {
- client.on('session_update', ({ topic, params }) => {
- const { namespaces } = params;
- const currentSession = client.session.get(topic);
- const updatedSession = { ...currentSession, namespaces };
- setSession(updatedSession);
- });
- },
- [setSession],
- );
-
- const onConnect = async () => {
- const proposalNamespace = {
- cosmos: {
- methods: ['cosmos_sendTokens'],
- chains: [`cosmos:${VITE_LACONICD_CHAIN_ID}`],
- events: [],
- },
- };
-
- try {
- const { uri, approval } = await signClient!.connect({
- requiredNamespaces: proposalNamespace,
- });
-
- if (uri) {
- walletConnectModal.openModal({ uri });
- const session = await approval();
- onSessionConnect(session);
- walletConnectModal.closeModal();
- }
- } catch (e) {
- console.error(e);
- }
- };
-
- const onDisconnect = useCallback(async () => {
- if (typeof signClient === 'undefined') {
- throw new Error('WalletConnect is not initialized');
- }
- if (typeof session === 'undefined') {
- throw new Error('Session is not connected');
- }
-
- await signClient.disconnect({
- topic: session.topic,
- reason: getSdkError('USER_DISCONNECTED'),
- });
-
- onSessionDelete();
- }, [signClient, session]);
-
- const onSessionDelete = () => {
- setAccounts([]);
- setSession(undefined);
- };
-
- const checkPersistedState = useCallback(
- async (signClient: SignClient) => {
- if (typeof signClient === 'undefined') {
- throw new Error('WalletConnect is not initialized');
- }
-
- if (typeof session !== 'undefined') return;
- if (signClient.session.length) {
- const lastKeyIndex = signClient.session.keys.length - 1;
- const previousSsession = signClient.session.get(
- signClient.session.keys[lastKeyIndex],
- );
-
- await onSessionConnect(previousSsession);
- return previousSsession;
- }
- },
- [session, onSessionConnect],
- );
-
- const createClient = useCallback(async () => {
- isSignClientInitializing.current = true;
- try {
- const signClient = await SignClient.init({
- projectId: VITE_WALLET_CONNECT_ID,
- metadata: {
- name: 'Deploy App',
- description: '',
- url: window.location.href,
- icons: ['https://avatars.githubusercontent.com/u/92608123'],
- },
- });
-
- setSignClient(signClient);
- await checkPersistedState(signClient);
- await subscribeToEvents(signClient);
- setLoadingSession(false);
- } catch (e) {
- console.error('error in createClient', e);
- }
- isSignClientInitializing.current = false;
- }, [setSignClient, checkPersistedState, subscribeToEvents]);
-
- useEffect(() => {
- if (!signClient && !isSignClientInitializing.current) {
- createClient();
- }
- }, [signClient, createClient]);
-
- useEffect(() => {
- const populateAccounts = async () => {
- if (!session) {
- return;
- }
- if (!session.namespaces['cosmos']) {
- console.log('Accounts for cosmos namespace not found');
- return;
- }
-
- const cosmosAddresses = session.namespaces['cosmos'].accounts;
-
- const cosmosAccounts = cosmosAddresses.map((address) => ({
- address,
- }));
-
- const allAccounts = cosmosAccounts;
-
- setAccounts(allAccounts);
- };
-
- populateAccounts();
- }, [session]);
-
- useEffect(() => {
- if (!signClient) {
- return;
- }
-
- signClient.on('session_delete', onSessionDelete);
-
- return () => {
- signClient.off('session_delete', onSessionDelete);
- };
- });
-
- return (
-
- {children}
-
- );
-};
diff --git a/packages/frontend/src/index.tsx b/packages/frontend/src/index.tsx
index 787cef61..862eaf67 100644
--- a/packages/frontend/src/index.tsx
+++ b/packages/frontend/src/index.tsx
@@ -4,10 +4,9 @@ import assert from 'assert';
import { GQLClient } from 'gql-client';
import { ThemeProvider } from '@snowballtools/material-tailwind-react-fork';
-
-import './index.css';
import '@fontsource/inter';
import '@fontsource-variable/jetbrains-mono';
+
import App from './App';
import reportWebVitals from './reportWebVitals';
import { GQLClientProvider } from './context/GQLClientContext';
@@ -16,7 +15,7 @@ import { Toaster } from 'components/shared/Toast';
import { LogErrorBoundary } from 'utils/log-error';
import { BASE_URL } from 'utils/constants';
import Web3ModalProvider from './context/Web3Provider';
-import { WalletConnectClientProvider } from 'context/WalletConnectContext';
+import './index.css';
console.log(`v-0.0.9`);
@@ -32,16 +31,14 @@ const gqlClient = new GQLClient({ gqlEndpoint });
root.render(
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
,
);
diff --git a/packages/frontend/src/pages/org-slug/projects/Id.tsx b/packages/frontend/src/pages/org-slug/projects/Id.tsx
index 9abce252..fd8ce0e7 100644
--- a/packages/frontend/src/pages/org-slug/projects/Id.tsx
+++ b/packages/frontend/src/pages/org-slug/projects/Id.tsx
@@ -60,9 +60,9 @@ const Id = () => {
fetchProject(id);
}, [id]);
- const onUpdate = async () => {
+ const onUpdate = useCallback(async () => {
await fetchProject(id);
- };
+ }, [fetchProject, id]);
return (
diff --git a/packages/frontend/src/pages/org-slug/projects/create/layout.tsx b/packages/frontend/src/pages/org-slug/projects/create/layout.tsx
index 32c13b78..ab63c951 100644
--- a/packages/frontend/src/pages/org-slug/projects/create/layout.tsx
+++ b/packages/frontend/src/pages/org-slug/projects/create/layout.tsx
@@ -1,12 +1,14 @@
import { ComponentPropsWithoutRef } from 'react';
import { Link, Outlet, useParams } from 'react-router-dom';
+import { useMediaQuery } from 'usehooks-ts';
+
+import * as Dialog from '@radix-ui/react-dialog';
import { Heading } from 'components/shared/Heading';
import { WavyBorder } from 'components/shared/WavyBorder';
import { Button } from 'components/shared/Button';
import { CrossIcon } from 'components/shared/CustomIcon';
import { cn } from 'utils/classnames';
-import * as Dialog from '@radix-ui/react-dialog';
export interface CreateProjectLayoutProps
extends ComponentPropsWithoutRef<'section'> {}
@@ -16,6 +18,7 @@ export const CreateProjectLayout = ({
...props
}: CreateProjectLayoutProps) => {
const { orgSlug } = useParams();
+ const isDesktopView = useMediaQuery('(min-width: 720px)'); // md:
const closeBtnLink = `/${orgSlug}`;
@@ -28,72 +31,69 @@ export const CreateProjectLayout = ({
);
- return (
- <>
- {/* Desktop */}
-
-
-
- {heading}
+ return isDesktopView ? (
+ // Desktop
+
+
+
+ {heading}
- {/* Cannot save btn as variable since responsive variant don't work with compoundVariant */}
-
- }
- aria-label="close"
- />
-
-
-
+ {/* Cannot save btn as variable since responsive variant don't work with compoundVariant */}
+
+
}
+ aria-label="close"
+ />
+
-
-
+
+
+
+
+ ) : (
+ // Mobile
+ // Setting modal={false} so even if modal is active on desktop, it doesn't block clicks
+
+
+ {/* Not using since modal={false} disables it and its content will not show */}
+
+
+ {/* Heading */}
+
+ {heading}
+
+
+ }
+ aria-label="close"
+ size="sm"
+ />
+
+
+
- {/* Mobile */}
- {/* Setting modal={false} so even if modal is active on desktop, it doesn't block clicks */}
-
-
- {/* Not using since modal={false} disables it and its content will not show */}
-
-
- {/* Heading */}
-
- {heading}
-
-
- }
- aria-label="close"
- size="sm"
- />
-
-
-
+ {/* Border */}
+
- {/* Border */}
-
-
- {/* Page content */}
-
-
-
-
-
-
-
- >
+ {/* Page content */}
+
+
+
+
+
+
+
);
};
diff --git a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx
index a129250f..7732a6e6 100644
--- a/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx
+++ b/packages/frontend/src/pages/org-slug/projects/id/Overview.tsx
@@ -24,6 +24,7 @@ import { Domain, DomainStatus } from 'gql-client';
import { AuctionCard } from 'components/projects/project/overview/Activity/AuctionCard';
const COMMITS_PER_PAGE = 4;
+const PROJECT_UPDATE_WAIT_MS = 5000;
const OverviewTabPanel = () => {
const { octokit } = useOctokit();
@@ -33,8 +34,7 @@ const OverviewTabPanel = () => {
const [liveDomain, setLiveDomain] = useState
();
const client = useGQLClient();
-
- const { project } = useOutletContext();
+ const { project, onUpdate } = useOutletContext();
useEffect(() => {
setFetchingActivities(true);
@@ -96,7 +96,16 @@ const OverviewTabPanel = () => {
};
fetchRepoActivity();
- }, [octokit, project]);
+ }, [project.repository]);
+
+ useEffect(() => {
+ onUpdate();
+ const timerId = setInterval(() => {
+ onUpdate();
+ }, PROJECT_UPDATE_WAIT_MS);
+
+ return () => clearInterval(timerId);
+ }, [onUpdate]);
useEffect(() => {
const fetchLiveProdDomain = async () => {
diff --git a/packages/frontend/src/pages/org-slug/projects/id/settings/General.tsx b/packages/frontend/src/pages/org-slug/projects/id/settings/General.tsx
index 4b886151..7a257d8d 100644
--- a/packages/frontend/src/pages/org-slug/projects/id/settings/General.tsx
+++ b/packages/frontend/src/pages/org-slug/projects/id/settings/General.tsx
@@ -18,7 +18,6 @@ const GeneralTabPanel = () => {
const client = useGQLClient();
const { toast } = useToast();
const { project, onUpdate } = useOutletContext();
- console.log(project);
const [transferOrganizations, setTransferOrganizations] = useState<
SelectOption[]
diff --git a/packages/frontend/src/utils/constants.ts b/packages/frontend/src/utils/constants.ts
index 446d9d58..046dd444 100644
--- a/packages/frontend/src/utils/constants.ts
+++ b/packages/frontend/src/utils/constants.ts
@@ -12,3 +12,4 @@ export const VITE_WALLET_CONNECT_ID = import.meta.env.VITE_WALLET_CONNECT_ID;
export const VITE_BUGSNAG_API_KEY = import.meta.env.VITE_BUGSNAG_API_KEY;
export const VITE_LIT_RELAY_API_KEY = import.meta.env.VITE_LIT_RELAY_API_KEY;
export const VITE_LACONICD_CHAIN_ID = import.meta.env.VITE_LACONICD_CHAIN_ID;
+export const VITE_WALLET_IFRAME_URL = import.meta.env.VITE_WALLET_IFRAME_URL;