handleTemplateSelect(template)}
- >
- {/* Template Icon */}
-
-
- {template.icon === 'web' ? 'PWA' : template.icon === 'nextjs' ? 'N' : 'IMG'}
+ {AVAILABLE_TEMPLATES.filter((t) => !t.isComingSoon).map(
+ (template) => (
+
handleTemplateSelect(template)}
+ >
+ {/* Template Icon */}
+
+
+ {template.icon === 'web'
+ ? 'PWA'
+ : template.icon === 'nextjs'
+ ? 'N'
+ : 'IMG'}
+
-
-
- {/* Template Info */}
-
-
{template.name}
-
-
- {template.repoFullName}
+
+ {/* Template Info */}
+
+
+ {template.name}
+
+
+
+ {template.repoFullName}
+
+
+ {/* Selection Indicator */}
+ {selectedTemplate?.id === template.id && (
+
+ )}
-
- {/* Selection Indicator */}
- {selectedTemplate?.id === template.id && (
-
- )}
-
- ))}
-
+ )
+ )}
+
{/* Project Name Input for Templates */}
{selectedTemplate && (
@@ -435,15 +498,20 @@ export function ConnectStep() {
)}
)}
-
+
{/* Navigation */}
-
@@ -451,4 +519,4 @@ export function ConnectStep() {
)
-}
\ No newline at end of file
+}
diff --git a/apps/deploy-fe/src/components/onboarding/deploy-step/deploy-step.tsx b/apps/deploy-fe/src/components/onboarding/deploy-step/deploy-step.tsx
index 91f7746..5c404e8 100644
--- a/apps/deploy-fe/src/components/onboarding/deploy-step/deploy-step.tsx
+++ b/apps/deploy-fe/src/components/onboarding/deploy-step/deploy-step.tsx
@@ -1,45 +1,57 @@
// src/components/onboarding/deploy-step/deploy-step.tsx
'use client'
-import { useState, useEffect } from 'react'
-import { useTheme } from 'next-themes'
-import { Github, Loader2, AlertTriangle, CheckCircle2 } from 'lucide-react'
-import { useOnboarding } from '@/components/onboarding/store'
+import { useOnboarding } from '@/components/onboarding/useOnboarding'
import { useWallet } from '@/context/WalletContext'
import { useDeployment } from '@/hooks/useDeployment'
import { useTemplateDeployment } from '@/hooks/useTemplate'
-import { Button } from '@workspace/ui/components/button'
-import { Progress } from '@workspace/ui/components/progress'
-import { Dialog, DialogContent, DialogTitle, DialogDescription, DialogFooter } from '@workspace/ui/components/dialog'
import { Alert, AlertDescription } from '@workspace/ui/components/alert'
-import { Card, CardContent, CardHeader, CardTitle } from '@workspace/ui/components/card'
import { Badge } from '@workspace/ui/components/badge'
+import { Button } from '@workspace/ui/components/button'
+import {
+ Card,
+ CardContent,
+ CardHeader,
+ CardTitle
+} from '@workspace/ui/components/card'
+import {
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogTitle
+} from '@workspace/ui/components/dialog'
+import { Progress } from '@workspace/ui/components/progress'
+import { AlertTriangle, CheckCircle2, Github, Loader2 } from 'lucide-react'
+import { useTheme } from 'next-themes'
+import { useEffect, useState } from 'react'
import { toast } from 'sonner'
export function DeployStep() {
const { previousStep, nextStep, formData, setFormData } = useOnboarding()
const { resolvedTheme } = useTheme()
const [mounted, setMounted] = useState(false)
-
+
// State
const [showConfirmDialog, setShowConfirmDialog] = useState(false)
const [deploymentError, setDeploymentError] = useState
(null)
const [deploymentSuccess, setDeploymentSuccess] = useState(false)
-
+
// Contexts and hooks
const { wallet } = useWallet()
const { deployRepository, isDeploying: isRepoDeploying } = useDeployment()
- const { deployTemplate, isDeploying: isTemplateDeploying } = useTemplateDeployment()
-
+ const { deployTemplate, isDeploying: isTemplateDeploying } =
+ useTemplateDeployment()
+
// Determine deployment type and get the right deploying state
const isTemplateMode = formData.deploymentMode === 'template'
const isDeploying = isTemplateMode ? isTemplateDeploying : isRepoDeploying
-
+
// Handle hydration mismatch by waiting for mount
useEffect(() => {
setMounted(true)
}, [])
-
+
// Get deployment info
const getDeploymentInfo = () => {
if (isTemplateMode) {
@@ -53,50 +65,53 @@ export function DeployStep() {
return {
name: formData.githubRepo?.split('/').pop() || 'Repository',
source: formData.githubRepo || 'Unknown Repository',
- projectName: formData.projectName || formData.githubRepo?.split('/').pop() || 'New Project',
+ projectName:
+ formData.projectName ||
+ formData.githubRepo?.split('/').pop() ||
+ 'New Project',
type: 'Repository'
}
}
}
-
+
const deploymentInfo = getDeploymentInfo()
-
+
// Open the confirmation modal
const handlePayAndDeploy = () => {
if (!wallet?.address) {
toast.error('Wallet not connected')
return
}
-
+
if (!formData.selectedOrg) {
toast.error('No organization selected')
return
}
-
+
if (isTemplateMode && (!formData.template || !formData.projectName)) {
toast.error('Template or project name missing')
return
}
-
+
if (!isTemplateMode && !formData.githubRepo) {
toast.error('Repository not selected')
return
}
-
+
setShowConfirmDialog(true)
}
-
+
// Close the confirmation modal
const handleCancelConfirm = () => {
setShowConfirmDialog(false)
}
-
+
// Handle confirmed deployment
const handleConfirmDeploy = async () => {
setShowConfirmDialog(false)
setDeploymentError(null)
setDeploymentSuccess(false)
-
+
try {
if (isTemplateMode) {
await deployTemplateProject()
@@ -105,16 +120,18 @@ export function DeployStep() {
}
} catch (error) {
console.error('Deployment failed:', error)
- setDeploymentError(error instanceof Error ? error.message : 'Deployment failed')
+ setDeploymentError(
+ error instanceof Error ? error.message : 'Deployment failed'
+ )
}
}
-
+
// Deploy template project
const deployTemplateProject = async () => {
if (!formData.template || !formData.projectName || !formData.selectedOrg) {
throw new Error('Missing required template deployment data')
}
-
+
const config = {
template: {
...formData.template,
@@ -125,9 +142,9 @@ export function DeployStep() {
organizationSlug: formData.selectedOrg,
environmentVariables: formData.environmentVariables || [],
deployerLrn: formData.selectedLrn
- };
- const result = await deployTemplate(config);
-
+ }
+ const result = await deployTemplate(config)
+
// Save deployment results
setFormData({
deploymentId: result.deploymentId,
@@ -135,85 +152,136 @@ export function DeployStep() {
projectId: result.projectId,
repositoryUrl: result.repositoryUrl
})
-
+
setDeploymentSuccess(true)
toast.success('Template deployed successfully!')
-
+
// Move to success step after short delay
setTimeout(() => {
nextStep()
}, 2000)
}
-
+
// Deploy repository project
const deployRepositoryProject = async () => {
if (!formData.githubRepo || !formData.selectedOrg) {
throw new Error('Missing required repository deployment data')
}
-
+
const config = {
projectId: '', // Will be generated by backend
organizationSlug: formData.selectedOrg,
repository: formData.githubRepo,
branch: 'main', // Default branch
- name: formData.projectName || formData.githubRepo.split('/').pop() || 'New Project',
+ name:
+ formData.projectName ||
+ formData.githubRepo.split('/').pop() ||
+ 'New Project',
environmentVariables: formData.environmentVariables || []
}
-
+
console.log('Deploying repository with config:', config)
-
+
const result = await deployRepository(config)
-
+
// Save deployment results
setFormData({
deploymentId: result.id,
deploymentUrl: result.url,
projectId: result.id
})
-
+
setDeploymentSuccess(true)
toast.success('Repository deployed successfully!')
-
+
// Move to success step after short delay
setTimeout(() => {
nextStep()
}, 2000)
}
-
+
// Don't render UI until after mount to prevent hydration mismatch
if (!mounted) {
return null
}
-
+
// Determine if dark mode is active
const isDarkMode = resolvedTheme === 'dark'
-
+
return (
<>
{/* Deploy icon */}
-
-
+
{/* Deploy header */}
-
+
{isDeploying ? 'Deploying...' : 'Deploy'}
- {isDeploying
- ? 'Your project is being deployed. This may take a few minutes.'
+ {isDeploying
+ ? 'Your project is being deployed. This may take a few minutes.'
: 'Review and confirm deployment'}
-
+
{/* Deployment Summary */}
@@ -226,13 +294,15 @@ export function DeployStep() {
-
{deploymentInfo.projectName}
+
+ {deploymentInfo.projectName}
+
{deploymentInfo.source}
-
+
Organization
@@ -240,21 +310,28 @@ export function DeployStep() {
Deployer
-
{formData.selectedLrn ? 'LRN' : 'Auction'}
-
-
-
- {formData.environmentVariables && formData.environmentVariables.length > 0 && (
-
-
Environment Variables
-
- {formData.environmentVariables.length} variable{formData.environmentVariables.length !== 1 ? 's' : ''} configured
+
+ {formData.selectedLrn ? 'LRN' : 'Auction'}
- )}
+
+
+ {formData.environmentVariables &&
+ formData.environmentVariables.length > 0 && (
+
+
+ Environment Variables
+
+
+ {formData.environmentVariables.length} variable
+ {formData.environmentVariables.length !== 1 ? 's' : ''}{' '}
+ configured
+
+
+ )}
-
+
{/* Error Display */}
{deploymentError && (
@@ -265,7 +342,7 @@ export function DeployStep() {
)}
-
+
{/* Success Display */}
{deploymentSuccess && (
@@ -273,40 +350,49 @@ export function DeployStep() {
Deployment Successful!
- Your project has been deployed successfully. You'll be redirected to the project dashboard.
+ Your project has been deployed successfully. You'll be
+ redirected to the project dashboard.
)}
-
+
{/* Deployment Progress - Only show while deploying */}
{isDeploying && (
-
- {isTemplateMode ? 'Creating repository from template...' : 'Deploying repository...'}
+
+ {isTemplateMode
+ ? 'Creating repository from template...'
+ : 'Deploying repository...'}
-
+
- This process may take several minutes. Please do not close this window.
+ This process may take several minutes. Please do not close this
+ window.
)}
-
+
{/* Navigation buttons */}
-
-
+
{deploymentSuccess ? (
-
) : isDeploying ? (
-
) : (
-
)}
-
+
{/* Transaction Confirmation Dialog */}
-
+
{/* Wallet Info */}
Payment Address
@@ -372,17 +473,19 @@ export function DeployStep() {
{wallet?.address}
-
+
{/* Deployer Info */}
{formData.selectedLrn && (
)}
-
+
{/* Cost Info */}
{formData.deploymentType === 'auction' && (