import { useCallback, useState, useEffect } from 'react'; import { useForm, Controller } from 'react-hook-form'; import { FormProvider, FieldValues } from 'react-hook-form'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { useMediaQuery } from 'usehooks-ts'; import { AddEnvironmentVariableInput, AuctionParams, Deployer, } from 'gql-client'; import { Select, MenuItem, FormControl, FormHelperText } from '@mui/material'; import { ArrowRightCircleFilledIcon, LoadingIcon, } from 'components/shared/CustomIcon'; import { Heading } from '../../shared/Heading'; import { Button } from '../../shared/Button'; import { Input } from 'components/shared/Input'; import { useToast } from 'components/shared/Toast'; import { useGQLClient } from '../../../context/GQLClientContext'; import EnvironmentVariablesForm from 'pages/org-slug/projects/id/settings/EnvironmentVariablesForm'; import { EnvironmentVariablesFormValues } from 'types/types'; import ConnectWallet from './ConnectWallet'; type ConfigureDeploymentFormValues = { option: string; lrn?: string; numProviders?: number; maxPrice?: string; }; type ConfigureFormValues = ConfigureDeploymentFormValues & EnvironmentVariablesFormValues; const Configure = () => { const [isLoading, setIsLoading] = useState(false); const [deployers, setDeployers] = useState([]); const [searchParams] = useSearchParams(); const templateId = searchParams.get('templateId'); const queryParams = new URLSearchParams(location.search); const owner = queryParams.get('owner'); const name = queryParams.get('name'); const defaultBranch = queryParams.get('defaultBranch'); const fullName = queryParams.get('fullName'); const orgSlug = queryParams.get('orgSlug'); const templateOwner = queryParams.get('templateOwner'); const templateRepo = queryParams.get('templateRepo'); const isPrivate = queryParams.get('isPrivate') === 'true'; const navigate = useNavigate(); const { toast, dismiss } = useToast(); const client = useGQLClient(); const methods = useForm({ defaultValues: { option: 'Auction' }, }); const selectedOption = methods.watch('option'); const isTabletView = useMediaQuery('(min-width: 720px)'); // md: const buttonSize = isTabletView ? { size: 'lg' as const } : {}; const createProject = async ( data: FieldValues, envVariables: AddEnvironmentVariableInput[], senderAddress: string, txHash: string ): Promise => { setIsLoading(true); let projectId: string | null = null; try { let lrn: string | undefined; let auctionParams: AuctionParams | undefined; if (data.option === 'LRN') { lrn = data.lrn; } else if (data.option === 'Auction') { auctionParams = { numProviders: Number(data.numProviders!), maxPrice: data.maxPrice!.toString(), }; } if (templateId) { const projectData: any = { templateOwner, templateRepo, owner, name, isPrivate, paymentAddress: senderAddress, txHash }; const { addProjectFromTemplate } = await client.addProjectFromTemplate( orgSlug!, projectData, lrn, auctionParams, envVariables, ); projectId = addProjectFromTemplate.id; } else { const { addProject } = await client.addProject( orgSlug!, { name: `${owner}-${name}`, prodBranch: defaultBranch!, repository: fullName!, template: 'webapp', paymentAddress: senderAddress, txHash }, lrn, auctionParams, envVariables, ); projectId = addProject.id; } } catch (error) { console.error('Error creating project:', error); toast({ id: 'error-creating-project', title: 'Error creating project', variant: 'error', onDismiss: dismiss, }); } finally { setIsLoading(false); } if (projectId) { return projectId; } else { throw new Error('Project creation failed'); } }; const handleFormSubmit = useCallback( async (createFormData: FieldValues) => { // Send tx request to wallet -> amount = createFormData.maxPrice * createFormData.numProviders // Get address of sender account(from wallet connect session) and txHash(result.signature) const senderAddress = 'address'; const txHash = 'txHash'; const environmentVariables = createFormData.variables.map( (variable: any) => { return { key: variable.key, value: variable.value, environments: Object.entries(createFormData.environment) .filter(([, value]) => value === true) .map(([key]) => key.charAt(0).toUpperCase() + key.slice(1)), }; }, ); const projectId = await createProject( createFormData, environmentVariables, senderAddress, txHash ); await client.getEnvironmentVariables(projectId); if (templateId) { createFormData.option === 'Auction' ? navigate( `/${orgSlug}/projects/create/success/${projectId}?isAuction=true`, ) : navigate( `/${orgSlug}/projects/create/template/deploy?projectId=${projectId}&templateId=${templateId}`, ); } else { createFormData.option === 'Auction' ? navigate( `/${orgSlug}/projects/create/success/${projectId}?isAuction=true`, ) : navigate( `/${orgSlug}/projects/create/deploy?projectId=${projectId}`, ); } }, [client, createProject, dismiss, toast], ); const fetchDeployers = useCallback(async () => { const res = await client.getDeployers(); setDeployers(res.deployers); }, [client]); useEffect(() => { fetchDeployers(); }, []); return (
Configure deployment The app can be deployed by setting the deployer LRN for a single deployment or by creating a deployer auction for multiple deployments
( )} />
{selectedOption === 'LRN' && (
The app will be deployed by the configured deployer ( Select deployer LRN {fieldState.error && ( {fieldState.error.message} )} )} />
)} {selectedOption === 'Auction' && ( <>
Set the number of deployers and maximum price for each deployment Number of Deployers ( )} />
Maximum Price (alnt) ( )} />
)} Environment Variables
); }; export default Configure;