Skip to content

Commit

Permalink
Add Solana to my projects (#3533)
Browse files Browse the repository at this point in the history
* add Solana to my projects

* add chainType to addRecipientAddressToProject

* fix address suggestion

* improve var definition

* remove unused JSX and styled component

* merge develop

* fix typo
  • Loading branch information
RamRamez authored Jan 9, 2024
1 parent d749e0f commit 0eb95ad
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 109 deletions.
8 changes: 7 additions & 1 deletion src/apollo/gql/gqlProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -441,11 +441,17 @@ export const UPDATE_PROJECT = gql`
`;

export const ADD_RECIPIENT_ADDRESS_TO_PROJECT = gql`
mutation ($projectId: Float!, $networkId: Float!, $address: String!) {
mutation (
$projectId: Float!
$networkId: Float!
$address: String!
$chainType: ChainType
) {
addRecipientAddressToProject(
projectId: $projectId
networkId: $networkId
address: $address
chainType: $chainType
) {
id
title
Expand Down
111 changes: 60 additions & 51 deletions src/components/modals/ManageProjectAddresses/AddNewAddress.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@ import styled from 'styled-components';
import { useForm } from 'react-hook-form';
import { Dispatch, FC, SetStateAction, useState } from 'react';
import { getAddress, isAddress } from 'viem';
import { type Address } from 'wagmi';
import { Chain } from 'wagmi';
import { IProject, IWalletAddress } from '@/apollo/types/types';
import Input from '../../Input';
import { requiredOptions } from '@/lib/constants/regex';
import { client } from '@/apollo/apolloClient';
import { ADD_RECIPIENT_ADDRESS_TO_PROJECT } from '@/apollo/gql/gqlProjects';
import InlineToast, { EToastType } from '../../toasts/InlineToast';
import { suggestNewAddress } from '@/lib/helpers';
import { ChainType, NonEVMChain } from '@/types/config';
import { isSolanaAddress } from '@/lib/wallet';
import { getChainName } from '@/lib/network';

interface IAddNewAddress {
project: IProject;
selectedWallet: IWalletAddress;
selectedChain: Chain | NonEVMChain;
setProjects: Dispatch<SetStateAction<IProject[]>>;
setSelectedWallet: Dispatch<SetStateAction<IWalletAddress | undefined>>;
setSelectedChain: Dispatch<SetStateAction<Chain | NonEVMChain | undefined>>;
setAddresses: Dispatch<SetStateAction<IWalletAddress[]>>;
}

Expand All @@ -27,9 +29,9 @@ interface IAddressForm {

export const AddNewAddress: FC<IAddNewAddress> = ({
project,
selectedWallet,
selectedChain,
setProjects,
setSelectedWallet,
setSelectedChain,
setAddresses,
}) => {
const [loading, setLoading] = useState(false);
Expand All @@ -40,17 +42,21 @@ export const AddNewAddress: FC<IAddNewAddress> = ({
setError,
} = useForm<IAddressForm>({ mode: 'onSubmit', reValidateMode: 'onSubmit' });

const chainType =
'chainType' in selectedChain ? selectedChain.chainType : undefined;

const handleAdd = async (formData: IAddressForm) => {
setLoading(true);
const { address } = formData;
console.log('ASD1', address);
try {
const _address = getAddress(address) as Address;
const _address =
chainType === ChainType.SOLANA ? address : getAddress(address);
await client.mutate({
mutation: ADD_RECIPIENT_ADDRESS_TO_PROJECT,
variables: {
projectId: Number(project.id),
networkId: selectedWallet.networkId,
networkId: selectedChain.id,
chainType,
address: _address,
},
});
Expand All @@ -65,26 +71,26 @@ export const AddNewAddress: FC<IAddNewAddress> = ({
{
address: _address,
isRecipient: true,
networkId: selectedWallet.networkId,
networkId: selectedChain.id,
chainType,
},
];
newProjects.push(structuredClone(_project));
} else {
newProjects.push(_project);
}
}
setSelectedWallet(undefined);
setSelectedChain(undefined);
return newProjects;
});
setAddresses(_addresses => {
const _adds = structuredClone(_addresses);
for (let i = 0; i < _adds.length; i++) {
const _add = _adds[i];
if (_add.networkId === selectedWallet.networkId) {
_add.isRecipient = true;
_add.address = _address;
}
}
_adds.push({
address: _address,
isRecipient: true,
networkId: selectedChain.id,
chainType,
});
return _adds;
});
} catch (error: any) {
Expand All @@ -102,52 +108,55 @@ export const AddNewAddress: FC<IAddNewAddress> = ({

const validateAddress = async (address: string) => {
setLoading(true);
if (!isAddress(address)) {
if (chainType === ChainType.SOLANA) {
if (!isSolanaAddress(address)) {
setLoading(false);
return 'Invalid Solana address';
}
} else if (!isAddress(address)) {
setLoading(false);
return 'Invalid address';
return 'Invalid ETH address';
}
return true;
};

const chainName = getChainName(selectedWallet.networkId);
const chainName = getChainName(selectedChain.id, chainType);

return (
<>
<form onSubmit={handleSubmit(handleAdd)}>
<StyledInput
register={register}
registerName='address'
autoFocus
label={`Receiving address on
${chainName}`}
registerOptions={{
...requiredOptions.walletAddress,
validate: validateAddress,
}}
placeholder='0x...'
defaultValue={suggestNewAddress(project.addresses)}
caption={`You can enter a new address to receive funds on ${chainName} network.`}
/>
{errors.address && (
<StyledInlineToast
type={EToastType.Error}
message={errors.address?.message as string}
/>
<form onSubmit={handleSubmit(handleAdd)}>
<StyledInput
register={register}
registerName='address'
autoFocus
label={`Receiving address on ${chainName}`}
registerOptions={{
...requiredOptions.walletAddress,
validate: validateAddress,
}}
placeholder='0x...'
defaultValue={suggestNewAddress(
project.addresses!,
selectedChain,
)}
<StyledButton
size='small'
label='SAVE ADDRESS'
buttonType='secondary'
type='submit'
loading={loading}
caption={`You can enter a new address to receive funds on ${chainName} network.`}
/>
{errors.address && (
<InlineToast
type={EToastType.Error}
message={errors.address?.message as string}
/>
</form>
</>
)}
<StyledButton
size='small'
label='SAVE ADDRESS'
buttonType='secondary'
type='submit'
loading={loading}
/>
</form>
);
};

const StyledInlineToast = styled(InlineToast)``;

const StyledInput = styled(Input)`
margin-top: 24px;
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import {
SublineBold,
} from '@giveth/ui-design-system';
import styled from 'styled-components';
import { FC, useState, useEffect, Dispatch, SetStateAction } from 'react';
import { FC, useState, Dispatch, SetStateAction } from 'react';
import { useIntl } from 'react-intl';
import { Chain } from 'wagmi';
import { useModalAnimation } from '@/hooks/useModalAnimation';
import { Modal } from '../Modal';
import { mediaQueries } from '@/lib/constants/constants';
Expand All @@ -16,68 +17,56 @@ import config from '@/configuration';
import { NetworkWalletAddress } from './NetworkWalletAddress';
import { AddNewAddress } from './AddNewAddress';
import { getChainName } from '@/lib/network';
import { NonEVMChain } from '@/types/config';
import type { IModal } from '@/types/common';

const networksConfig = config.EVM_NETWORKS_CONFIG;
const networkIds = Object.keys(networksConfig).map(Number);
const { CHAINS } = config;

interface IManageProjectAddressesModal extends IModal {
interface IModalProps extends IModal {
project: IProject;
setProjects: Dispatch<SetStateAction<IProject[]>>;
}

export const ManageProjectAddressesModal: FC<IManageProjectAddressesModal> = ({
project,
setShowModal,
setProjects,
}) => {
const [selectedWallet, setSelectedWallet] = useState<IWalletAddress>();
const [addresses, setAddresses] = useState<IWalletAddress[]>([]);
export const ManageProjectAddressesModal: FC<IModalProps> = props => {
const { project, setShowModal, setProjects } = props;
const [selectedChain, setSelectedChain] = useState<Chain | NonEVMChain>();
const [addresses, setAddresses] = useState<IWalletAddress[]>(
project.addresses || [],
);
const { isAnimating, closeModal } = useModalAnimation(setShowModal);
const { formatMessage } = useIntl();

useEffect(() => {
let WalletAddr: { [key: number]: IWalletAddress } = {};
networkIds.forEach(networkId => {
WalletAddr[networkId] = { networkId };
});
const { addresses } = project;
if (!addresses) return;
for (let i = 0; i < addresses.length; i++) {
const address = addresses[i];
if (address.networkId) {
WalletAddr[address.networkId] = address;
}
}
setAddresses(Object.values(WalletAddr));
}, [project]);
const selectedChainType =
selectedChain && 'chainType' in selectedChain
? selectedChain.chainType
: undefined;

return (
<Modal
headerIcon={<IconWalletOutline32 />}
headerTitle={formatMessage({
id: selectedWallet
id: selectedChain
? 'label.add_new_address'
: 'label.manage_addresses',
})}
closeModal={closeModal}
isAnimating={isAnimating}
headerTitlePosition='left'
backButtonCallback={
selectedWallet ? () => setSelectedWallet(undefined) : undefined
selectedChain ? () => setSelectedChain(undefined) : undefined
}
>
<ModalContainer>
<Content>
{selectedWallet ? (
{selectedChain ? (
<SublineBold>
{formatMessage(
{
id: 'label.chain_address',
},
{
chainName: getChainName(
selectedWallet.networkId,
selectedChain.id,
selectedChainType,
),
},
)}
Expand All @@ -93,20 +82,21 @@ export const ManageProjectAddressesModal: FC<IManageProjectAddressesModal> = ({
</>
)}
</Content>
{selectedWallet ? (
{selectedChain ? (
<AddNewAddress
project={project}
selectedWallet={selectedWallet}
selectedChain={selectedChain}
setProjects={setProjects}
setSelectedWallet={setSelectedWallet}
setSelectedChain={setSelectedChain}
setAddresses={setAddresses}
/>
) : (
addresses.map((addr, index) => (
CHAINS.map(chain => (
<NetworkWalletAddress
key={index}
networkWallet={addr}
setSelectedWallet={setSelectedWallet}
key={chain.name}
chain={chain}
addresses={addresses}
setSelectedChain={setSelectedChain}
/>
))
)}
Expand Down
Loading

0 comments on commit 0eb95ad

Please sign in to comment.