removed useOnboarding hook and used store.ts instead, modified all dependencies accordingly
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
import { ConfigureStep } from '@/components/onboarding/configure-step'
|
||||
import { ConnectStep } from '@/components/onboarding/connect-step'
|
||||
import { DeployStep } from '@/components/onboarding/deploy-step'
|
||||
import { useOnboarding } from '@/components/onboarding/useOnboarding'
|
||||
import { useOnboarding } from '@/components/onboarding/store'
|
||||
import { ScrollArea } from '@workspace/ui/components/scroll-area'
|
||||
import { SidebarNav } from './sidebar'
|
||||
|
||||
|
||||
@@ -241,16 +241,26 @@
|
||||
// export default OnboardingDialog
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { X, Github } from 'lucide-react'
|
||||
import { Button } from '@workspace/ui/components/button'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@workspace/ui/components/select'
|
||||
import { useOnboarding } from '@/components/onboarding/useOnboarding'
|
||||
import { ScrollableRepoList } from '@/components/onboarding/connect-step/repository-list'
|
||||
import { TemplateList } from '@/components/onboarding/connect-step/template-list'
|
||||
import { useOnboarding } from '@/components/onboarding/store'
|
||||
import { useRepoData } from '@/hooks/useRepoData'
|
||||
import { Dialog, DialogContent, DialogTitle } from '@workspace/ui/components/dialog'
|
||||
import { VisuallyHidden } from '@radix-ui/react-visually-hidden'
|
||||
import { Button } from '@workspace/ui/components/button'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle
|
||||
} from '@workspace/ui/components/dialog'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue
|
||||
} from '@workspace/ui/components/select'
|
||||
import { Github, X } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface OnboardingDialogProps {
|
||||
trigger?: React.ReactNode
|
||||
@@ -269,18 +279,21 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
defaultOpen = false,
|
||||
onClose
|
||||
}) => {
|
||||
const { nextStep, setFormData, formData, currentStep, previousStep } = useOnboarding()
|
||||
const [selectedRepo, setSelectedRepo] = useState<string>(formData.githubRepo || '')
|
||||
const { nextStep, setFormData, formData, currentStep, previousStep } =
|
||||
useOnboarding()
|
||||
const [selectedRepo, setSelectedRepo] = useState<string>(
|
||||
formData.githubRepo || ''
|
||||
)
|
||||
const [isImportMode, setIsImportMode] = useState(true)
|
||||
const [isOpen, setIsOpen] = useState(defaultOpen)
|
||||
const { repoData: repositories, isLoading } = useRepoData('')
|
||||
|
||||
|
||||
// Handle repository selection
|
||||
const handleRepoSelect = (repo: string) => {
|
||||
setSelectedRepo(repo)
|
||||
setFormData({ githubRepo: repo })
|
||||
}
|
||||
|
||||
|
||||
// Handle mode toggle between import and template
|
||||
const toggleMode = (mode: 'import' | 'template') => {
|
||||
setIsImportMode(mode === 'import')
|
||||
@@ -293,7 +306,7 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<Dialog open={isOpen} onOpenChange={handleOpenChange}>
|
||||
{trigger && trigger}
|
||||
@@ -301,25 +314,48 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
<VisuallyHidden>
|
||||
<DialogTitle>Onboarding</DialogTitle>
|
||||
</VisuallyHidden>
|
||||
|
||||
|
||||
<div className="flex h-full w-full">
|
||||
{/* Left sidebar with steps */}
|
||||
<div className="w-[280px] bg-zinc-950 p-8 relative overflow-hidden">
|
||||
{/* Laconic logo */}
|
||||
<div className="flex items-center mb-12">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="mr-2">
|
||||
<path d="M12 16L4 8L12 0L20 8L12 16Z" fill="white"/>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="mr-2"
|
||||
>
|
||||
<path d="M12 16L4 8L12 0L20 8L12 16Z" fill="white" />
|
||||
</svg>
|
||||
<span className="text-white text-xl font-bold">LACONIC</span>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Steps */}
|
||||
<div className="space-y-10">
|
||||
{/* Connect step */}
|
||||
<div className="flex">
|
||||
<div className="mr-4">
|
||||
<div className={`w-10 h-10 rounded-lg ${currentStep === 'connect' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}>
|
||||
<svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" className={currentStep === 'connect' ? 'text-black' : 'text-zinc-400'}>
|
||||
<div
|
||||
className={`w-10 h-10 rounded-lg ${currentStep === 'connect' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
height="20"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={
|
||||
currentStep === 'connect'
|
||||
? 'text-black'
|
||||
: 'text-zinc-400'
|
||||
}
|
||||
>
|
||||
<path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
|
||||
<line x1="8" y1="12" x2="16" y2="12"></line>
|
||||
</svg>
|
||||
@@ -327,16 +363,40 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
<div className="w-px h-16 bg-zinc-800 mx-auto mt-2"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={`font-medium text-base ${currentStep === 'connect' ? 'text-white' : 'text-zinc-400'}`}>Connect</h3>
|
||||
<p className={`text-sm ${currentStep === 'connect' ? 'text-zinc-400' : 'text-zinc-500'}`}>Connect and import a GitHub repo</p>
|
||||
<h3
|
||||
className={`font-medium text-base ${currentStep === 'connect' ? 'text-white' : 'text-zinc-400'}`}
|
||||
>
|
||||
Connect
|
||||
</h3>
|
||||
<p
|
||||
className={`text-sm ${currentStep === 'connect' ? 'text-zinc-400' : 'text-zinc-500'}`}
|
||||
>
|
||||
Connect and import a GitHub repo
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Configure step */}
|
||||
<div className="flex">
|
||||
<div className="mr-4">
|
||||
<div className={`w-10 h-10 rounded-lg ${currentStep === 'configure' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}>
|
||||
<svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" className={currentStep === 'configure' ? 'text-black' : 'text-zinc-400'}>
|
||||
<div
|
||||
className={`w-10 h-10 rounded-lg ${currentStep === 'configure' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
height="20"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={
|
||||
currentStep === 'configure'
|
||||
? 'text-black'
|
||||
: 'text-zinc-400'
|
||||
}
|
||||
>
|
||||
<path d="M12 20h9"></path>
|
||||
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>
|
||||
</svg>
|
||||
@@ -344,59 +404,110 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
<div className="w-px h-16 bg-zinc-800 mx-auto mt-2"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={`font-medium text-base ${currentStep === 'configure' ? 'text-white' : 'text-zinc-400'}`}>Configure</h3>
|
||||
<p className={`text-sm ${currentStep === 'configure' ? 'text-zinc-400' : 'text-zinc-500'}`}>Define the deployment type</p>
|
||||
<h3
|
||||
className={`font-medium text-base ${currentStep === 'configure' ? 'text-white' : 'text-zinc-400'}`}
|
||||
>
|
||||
Configure
|
||||
</h3>
|
||||
<p
|
||||
className={`text-sm ${currentStep === 'configure' ? 'text-zinc-400' : 'text-zinc-500'}`}
|
||||
>
|
||||
Define the deployment type
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Deploy step */}
|
||||
<div className="flex">
|
||||
<div className="mr-4">
|
||||
<div className={`w-10 h-10 rounded-lg ${currentStep === 'deploy' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}>
|
||||
<svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" className={currentStep === 'deploy' ? 'text-black' : 'text-zinc-400'}>
|
||||
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
|
||||
<div
|
||||
className={`w-10 h-10 rounded-lg ${currentStep === 'deploy' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
height="20"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={
|
||||
currentStep === 'deploy'
|
||||
? 'text-black'
|
||||
: 'text-zinc-400'
|
||||
}
|
||||
>
|
||||
<rect
|
||||
x="2"
|
||||
y="2"
|
||||
width="20"
|
||||
height="20"
|
||||
rx="5"
|
||||
ry="5"
|
||||
></rect>
|
||||
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
|
||||
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={`font-medium text-base ${currentStep === 'deploy' ? 'text-white' : 'text-zinc-400'}`}>Deploy</h3>
|
||||
<p className={`text-sm ${currentStep === 'deploy' ? 'text-zinc-400' : 'text-zinc-500'}`}>Review and confirm deployment</p>
|
||||
<h3
|
||||
className={`font-medium text-base ${currentStep === 'deploy' ? 'text-white' : 'text-zinc-400'}`}
|
||||
>
|
||||
Deploy
|
||||
</h3>
|
||||
<p
|
||||
className={`text-sm ${currentStep === 'deploy' ? 'text-zinc-400' : 'text-zinc-500'}`}
|
||||
>
|
||||
Review and confirm deployment
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Background shape (decorative) */}
|
||||
<div className="absolute -bottom-32 -left-32 w-64 h-64 rounded-full bg-zinc-900 opacity-50"></div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Main content */}
|
||||
<div className="flex-1 bg-zinc-950 p-8 relative">
|
||||
{/* Close button */}
|
||||
<button
|
||||
<button
|
||||
className="absolute top-4 right-4 text-zinc-400 hover:text-white"
|
||||
onClick={() => handleOpenChange(false)}
|
||||
>
|
||||
<X size={24} />
|
||||
</button>
|
||||
|
||||
|
||||
{currentStep === 'connect' && (
|
||||
<div className="max-w-md mx-auto mt-8">
|
||||
{/* Connect icon */}
|
||||
<div className="flex justify-center mb-6">
|
||||
<svg viewBox="0 0 24 24" width="48" height="48" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" className="text-white">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width="48"
|
||||
height="48"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
fill="none"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="text-white"
|
||||
>
|
||||
<path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"></path>
|
||||
<line x1="8" y1="12" x2="16" y2="12"></line>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Connect header */}
|
||||
<h2 className="text-2xl font-medium text-white text-center mb-2">Connect</h2>
|
||||
<h2 className="text-2xl font-medium text-white text-center mb-2">
|
||||
Connect
|
||||
</h2>
|
||||
<p className="text-center text-zinc-400 mb-8">
|
||||
Connect and import a GitHub repo or start from a template
|
||||
</p>
|
||||
|
||||
|
||||
{/* Git account selector */}
|
||||
<div className="mb-4">
|
||||
<Select defaultValue="git-account">
|
||||
@@ -411,25 +522,25 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Mode buttons */}
|
||||
<div className="grid grid-cols-2 gap-2 mb-4">
|
||||
<Button
|
||||
variant={isImportMode ? "default" : "outline"}
|
||||
variant={isImportMode ? 'default' : 'outline'}
|
||||
className={`py-6 ${isImportMode ? 'bg-blue-600 hover:bg-blue-700 text-white' : 'bg-zinc-900 border-zinc-800 hover:bg-zinc-800 text-zinc-400'}`}
|
||||
onClick={() => toggleMode('import')}
|
||||
>
|
||||
Import a repository
|
||||
</Button>
|
||||
<Button
|
||||
variant={!isImportMode ? "default" : "outline"}
|
||||
variant={!isImportMode ? 'default' : 'outline'}
|
||||
className={`py-6 ${!isImportMode ? 'bg-blue-600 hover:bg-blue-700 text-white' : 'bg-zinc-900 border-zinc-800 hover:bg-zinc-800 text-zinc-400'}`}
|
||||
onClick={() => toggleMode('template')}
|
||||
>
|
||||
Start with a template
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Repository or template list */}
|
||||
{isImportMode ? (
|
||||
<div className="mb-8">
|
||||
@@ -445,11 +556,11 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
<TemplateList onSelect={() => {}} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{/* Navigation buttons */}
|
||||
<div className="flex justify-between items-center mt-8">
|
||||
<Button
|
||||
variant="outline"
|
||||
<Button
|
||||
variant="outline"
|
||||
className="text-zinc-400 bg-zinc-900 border-zinc-800 hover:bg-zinc-800"
|
||||
disabled={true}
|
||||
>
|
||||
@@ -460,8 +571,8 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
<div className="w-12 h-1 rounded-full bg-zinc-800"></div>
|
||||
<div className="w-12 h-1 rounded-full bg-zinc-800"></div>
|
||||
</div>
|
||||
<Button
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white"
|
||||
<Button
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white"
|
||||
onClick={nextStep}
|
||||
disabled={!selectedRepo && isImportMode}
|
||||
>
|
||||
@@ -470,24 +581,26 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{currentStep === 'configure' && (
|
||||
<div className="max-w-md mx-auto mt-8">
|
||||
{/* Configure content will go here */}
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-medium text-white mb-2">Configure</h2>
|
||||
<h2 className="text-2xl font-medium text-white mb-2">
|
||||
Configure
|
||||
</h2>
|
||||
<p className="text-zinc-400 mb-8">
|
||||
Define your deployment configuration
|
||||
</p>
|
||||
|
||||
|
||||
<div className="text-center mt-16 text-zinc-400">
|
||||
Configure step content will be implemented here
|
||||
</div>
|
||||
|
||||
|
||||
{/* Navigation buttons */}
|
||||
<div className="flex justify-between items-center mt-16">
|
||||
<Button
|
||||
variant="outline"
|
||||
<Button
|
||||
variant="outline"
|
||||
className="text-zinc-400 bg-zinc-900 border-zinc-800 hover:bg-zinc-800"
|
||||
onClick={() => previousStep()}
|
||||
>
|
||||
@@ -498,8 +611,8 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
<div className="w-12 h-1 rounded-full bg-blue-600"></div>
|
||||
<div className="w-12 h-1 rounded-full bg-zinc-800"></div>
|
||||
</div>
|
||||
<Button
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white"
|
||||
<Button
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white"
|
||||
onClick={nextStep}
|
||||
>
|
||||
Next
|
||||
@@ -508,24 +621,26 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
{currentStep === 'deploy' && (
|
||||
<div className="max-w-md mx-auto mt-8">
|
||||
{/* Deploy content will go here */}
|
||||
<div className="text-center">
|
||||
<h2 className="text-2xl font-medium text-white mb-2">Deploy</h2>
|
||||
<h2 className="text-2xl font-medium text-white mb-2">
|
||||
Deploy
|
||||
</h2>
|
||||
<p className="text-zinc-400 mb-8">
|
||||
Review and confirm your deployment
|
||||
</p>
|
||||
|
||||
|
||||
<div className="text-center mt-16 text-zinc-400">
|
||||
Deploy step content will be implemented here
|
||||
</div>
|
||||
|
||||
|
||||
{/* Navigation buttons */}
|
||||
<div className="flex justify-between items-center mt-16">
|
||||
<Button
|
||||
variant="outline"
|
||||
<Button
|
||||
variant="outline"
|
||||
className="text-zinc-400 bg-zinc-900 border-zinc-800 hover:bg-zinc-800"
|
||||
onClick={() => previousStep()}
|
||||
>
|
||||
@@ -536,9 +651,7 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
<div className="w-12 h-1 rounded-full bg-zinc-800"></div>
|
||||
<div className="w-12 h-1 rounded-full bg-blue-600"></div>
|
||||
</div>
|
||||
<Button
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white"
|
||||
>
|
||||
<Button className="bg-blue-600 hover:bg-blue-700 text-white">
|
||||
Deploy
|
||||
</Button>
|
||||
</div>
|
||||
@@ -552,4 +665,4 @@ const OnboardingDialog: React.FC<OnboardingDialogProps> = ({
|
||||
)
|
||||
}
|
||||
|
||||
export default OnboardingDialog
|
||||
export default OnboardingDialog
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { GitBranch, Settings, Box } from 'lucide-react'
|
||||
import type { Step } from '@/components/onboarding/useOnboarding'
|
||||
import type { Step } from '@/components/onboarding/types'
|
||||
import { Box, GitBranch, Settings } from 'lucide-react'
|
||||
|
||||
interface OnboardingSidebarProps {
|
||||
currentStep: Step
|
||||
@@ -12,58 +12,101 @@ export function OnboardingSidebar({ currentStep }: OnboardingSidebarProps) {
|
||||
<div className="w-[280px] bg-zinc-950 p-8 relative overflow-hidden">
|
||||
{/* Laconic logo */}
|
||||
<div className="flex items-center mb-12">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" className="mr-2">
|
||||
<path d="M12 16L4 8L12 0L20 8L12 16Z" fill="white"/>
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="mr-2"
|
||||
>
|
||||
<path d="M12 16L4 8L12 0L20 8L12 16Z" fill="white" />
|
||||
</svg>
|
||||
<span className="text-white text-xl font-bold">LACONIC</span>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Steps */}
|
||||
<div className="space-y-10">
|
||||
{/* Connect step */}
|
||||
<div className="flex">
|
||||
<div className="mr-4">
|
||||
<div className={`w-10 h-10 rounded-lg ${currentStep === 'connect' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}>
|
||||
<GitBranch className={`h-5 w-5 ${currentStep === 'connect' ? 'text-black' : 'text-zinc-400'}`} />
|
||||
<div
|
||||
className={`w-10 h-10 rounded-lg ${currentStep === 'connect' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}
|
||||
>
|
||||
<GitBranch
|
||||
className={`h-5 w-5 ${currentStep === 'connect' ? 'text-black' : 'text-zinc-400'}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-px h-16 bg-zinc-800 mx-auto mt-2"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={`font-medium text-base ${currentStep === 'connect' ? 'text-white' : 'text-zinc-400'}`}>Connect</h3>
|
||||
<p className={`text-sm ${currentStep === 'connect' ? 'text-zinc-400' : 'text-zinc-500'}`}>Connect and import a GitHub repo</p>
|
||||
<h3
|
||||
className={`font-medium text-base ${currentStep === 'connect' ? 'text-white' : 'text-zinc-400'}`}
|
||||
>
|
||||
Connect
|
||||
</h3>
|
||||
<p
|
||||
className={`text-sm ${currentStep === 'connect' ? 'text-zinc-400' : 'text-zinc-500'}`}
|
||||
>
|
||||
Connect and import a GitHub repo
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Configure step */}
|
||||
<div className="flex">
|
||||
<div className="mr-4">
|
||||
<div className={`w-10 h-10 rounded-lg ${currentStep === 'configure' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}>
|
||||
<Settings className={`h-5 w-5 ${currentStep === 'configure' ? 'text-black' : 'text-zinc-400'}`} />
|
||||
<div
|
||||
className={`w-10 h-10 rounded-lg ${currentStep === 'configure' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}
|
||||
>
|
||||
<Settings
|
||||
className={`h-5 w-5 ${currentStep === 'configure' ? 'text-black' : 'text-zinc-400'}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-px h-16 bg-zinc-800 mx-auto mt-2"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={`font-medium text-base ${currentStep === 'configure' ? 'text-white' : 'text-zinc-400'}`}>Configure</h3>
|
||||
<p className={`text-sm ${currentStep === 'configure' ? 'text-zinc-400' : 'text-zinc-500'}`}>Define the deployment type</p>
|
||||
<h3
|
||||
className={`font-medium text-base ${currentStep === 'configure' ? 'text-white' : 'text-zinc-400'}`}
|
||||
>
|
||||
Configure
|
||||
</h3>
|
||||
<p
|
||||
className={`text-sm ${currentStep === 'configure' ? 'text-zinc-400' : 'text-zinc-500'}`}
|
||||
>
|
||||
Define the deployment type
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Deploy step */}
|
||||
<div className="flex">
|
||||
<div className="mr-4">
|
||||
<div className={`w-10 h-10 rounded-lg ${currentStep === 'deploy' || currentStep === 'success' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}>
|
||||
<Box className={`h-5 w-5 ${currentStep === 'deploy' || currentStep === 'success' ? 'text-black' : 'text-zinc-400'}`} />
|
||||
<div
|
||||
className={`w-10 h-10 rounded-lg ${currentStep === 'deploy' || currentStep === 'success' ? 'bg-white' : 'bg-zinc-800'} flex items-center justify-center`}
|
||||
>
|
||||
<Box
|
||||
className={`h-5 w-5 ${currentStep === 'deploy' || currentStep === 'success' ? 'text-black' : 'text-zinc-400'}`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 className={`font-medium text-base ${currentStep === 'deploy' || currentStep === 'success' ? 'text-white' : 'text-zinc-400'}`}>Deploy</h3>
|
||||
<p className={`text-sm ${currentStep === 'deploy' || currentStep === 'success' ? 'text-zinc-400' : 'text-zinc-500'}`}>Review and confirm deployment</p>
|
||||
<h3
|
||||
className={`font-medium text-base ${currentStep === 'deploy' || currentStep === 'success' ? 'text-white' : 'text-zinc-400'}`}
|
||||
>
|
||||
Deploy
|
||||
</h3>
|
||||
<p
|
||||
className={`text-sm ${currentStep === 'deploy' || currentStep === 'success' ? 'text-zinc-400' : 'text-zinc-500'}`}
|
||||
>
|
||||
Review and confirm deployment
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Background shape (decorative) */}
|
||||
<div className="absolute -bottom-32 -left-32 w-64 h-64 rounded-full bg-zinc-900 opacity-50"></div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import { FileCog } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { useOnboarding } from '../store'
|
||||
|
||||
/**
|
||||
* Second step in the onboarding flow
|
||||
* Handles deployment configuration and environment setup
|
||||
*
|
||||
* Features:
|
||||
* - Deployment type selection (auction/LRN)
|
||||
* - Environment variable configuration
|
||||
* - Account selection
|
||||
*
|
||||
* @component
|
||||
*/
|
||||
export function ConfigureStep() {
|
||||
const { formData, setFormData } = useOnboarding()
|
||||
const [activeTab, setActiveTab] = useState<'create-auction' | 'deployer-lrn'>(
|
||||
'create-auction'
|
||||
)
|
||||
const [environments, setEnvironments] = useState({
|
||||
production: false,
|
||||
preview: false,
|
||||
development: false
|
||||
})
|
||||
|
||||
// const handleEnvironmentChange = (env: keyof typeof environments) => {
|
||||
// setEnvironments((prev) => ({
|
||||
// ...prev,
|
||||
// [env]: !prev[env],
|
||||
// }))
|
||||
// setFormData({
|
||||
// environmentVars: {
|
||||
// ...formData.environmentVars,
|
||||
// [env]: !environments[env],
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="max-w-2xl mx-auto space-y-8">
|
||||
<div className="flex flex-col items-center justify-center w-full max-w-[445px] mx-auto">
|
||||
<div className="w-full flex flex-col items-center gap-6">
|
||||
{/* Header section with icon and description */}
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<FileCog className="w-16 h-16 text-foreground" />
|
||||
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<h2 className="text-2xl font-bold text-foreground">
|
||||
Configure
|
||||
</h2>
|
||||
<p className="text-base text-muted-foreground text-center">
|
||||
Set the deployer LRN for a single deployment or by creating a
|
||||
deployer auction for multiple deployments
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
Content sections will be placed here: 1. Deployment type tabs
|
||||
(auction/LRN) 2. Configuration forms 3. Environment variables 4.
|
||||
Account selection ...content here/
|
||||
{/* <Configure /> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -73,12 +73,18 @@ export function ConnectStep() {
|
||||
} = useAuthStatus()
|
||||
|
||||
// Repository data
|
||||
const { repoData: repositories, isLoading: isLoadingRepos, error: repoError } = useRepoData('')
|
||||
|
||||
const {
|
||||
repoData: repositories,
|
||||
isLoading: isLoadingRepos,
|
||||
error: repoError
|
||||
} = useRepoData('')
|
||||
|
||||
// Debug repository data
|
||||
useEffect(() => {
|
||||
console.log('🔍 ConnectStep: Repository data changed:', {
|
||||
repositories: repositories ? `Array with ${Array.isArray(repositories) ? repositories.length : 'not array'} items` : 'null',
|
||||
repositories: repositories
|
||||
? `Array with ${Array.isArray(repositories) ? repositories.length : 'not array'} items`
|
||||
: 'null',
|
||||
isLoadingRepos,
|
||||
repoError,
|
||||
isFullyAuthenticated
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
// 'use client'
|
||||
|
||||
// import { Button } from '@workspace/ui/components/button'
|
||||
// import { useState } from 'react'
|
||||
// import { useOnboarding } from '../store'
|
||||
|
||||
// type ConnectState = 'initial' | 'repository-select' | 'template-select'
|
||||
|
||||
// /**
|
||||
// * First step in the onboarding flow
|
||||
// * Handles GitHub connection and repository selection
|
||||
// *
|
||||
// * States:
|
||||
// * - initial: Shows GitHub connect button
|
||||
// * - repository-select: Shows list of repositories
|
||||
// * - template-select: Shows available templates
|
||||
// *
|
||||
// * @component
|
||||
// */
|
||||
// export function ConnectStep() {
|
||||
// const [connectState, setConnectState] = useState<ConnectState>('initial')
|
||||
// const [projectName, setProjectName] = useState('')
|
||||
// const { setFormData, nextStep } = useOnboarding()
|
||||
|
||||
// const handleConnect = () => {
|
||||
// setConnectState('repository-select')
|
||||
// }
|
||||
|
||||
// return (
|
||||
// <div className="max-w-2xl w-full">
|
||||
// {/* <ConnectAccountTabPanel />\ */}
|
||||
// {connectState === 'initial' ? (
|
||||
// <div className="flex flex-col items-center justify-center gap-6 p-8">
|
||||
// <h2 className="text-2xl font-semibold text-center">
|
||||
// Connect to GitHub
|
||||
// </h2>
|
||||
// <p className="text-center text-muted-foreground">
|
||||
// Connect your GitHub account to get started
|
||||
// </p>
|
||||
// <Button onClick={handleConnect} />
|
||||
// </div>
|
||||
// ) : (
|
||||
// // <ConnectAccount onAuth={() => {}} />
|
||||
// <>...connect goes here</>
|
||||
// )}
|
||||
// </div>
|
||||
// )
|
||||
// }
|
||||
|
||||
'use client'
|
||||
// src/components/onboarding/connect-step/connect-step.tsx
|
||||
import { useState } from 'react'
|
||||
import { useRepoData } from '@/hooks/useRepoData'
|
||||
import { useOnboarding } from '@/components/onboarding/useOnboarding'
|
||||
import { ScrollableRepoList } from '@/components/onboarding/connect-step/repository-list'
|
||||
import { TemplateList } from '@/components/onboarding/connect-step/template-list'
|
||||
import { StepHeader } from '@/components/onboarding/common/step-header'
|
||||
import { Button } from '@workspace/ui/components/button'
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@workspace/ui/components/select'
|
||||
import { GitBranch } from 'lucide-react'
|
||||
|
||||
export const ConnectStep = () => {
|
||||
const { setFormData, formData, nextStep } = useOnboarding()
|
||||
const [selectedRepo, setSelectedRepo] = useState<string>(formData.githubRepo || '')
|
||||
const [isImportMode, setIsImportMode] = useState(true)
|
||||
const { repoData: repositories, isLoading } = useRepoData('')
|
||||
|
||||
// Handle repository selection
|
||||
const handleRepoSelect = (repo: string) => {
|
||||
setSelectedRepo(repo)
|
||||
setFormData({ githubRepo: repo })
|
||||
}
|
||||
|
||||
// Handle mode toggle between import and template
|
||||
const toggleMode = (mode: 'import' | 'template') => {
|
||||
setIsImportMode(mode === 'import')
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center w-full px-8">
|
||||
<div className="w-full max-w-md">
|
||||
{/* Connect icon */}
|
||||
<div className="flex justify-center mb-6">
|
||||
<div className="w-16 h-16 bg-blue-500 bg-opacity-10 rounded-full flex items-center justify-center">
|
||||
<GitBranch className="h-8 w-8 text-blue-500" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Connect header */}
|
||||
<StepHeader
|
||||
title="Connect"
|
||||
description="Connect and import a GitHub repo or start from a template"
|
||||
icon={<GitBranch />}
|
||||
/>
|
||||
|
||||
{/* Git account selector */}
|
||||
<Select defaultValue="git-account">
|
||||
<SelectTrigger className="mb-4 bg-zinc-900 border-zinc-800">
|
||||
<SelectValue placeholder="Select Git account" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="git-account">git-account</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
{/* Mode buttons */}
|
||||
<div className="flex mb-4 space-x-2">
|
||||
<Button
|
||||
variant={isImportMode ? "default" : "outline"}
|
||||
className={`flex-1 ${isImportMode ? 'bg-blue-600 hover:bg-blue-700' : 'bg-zinc-900 border-zinc-800 hover:bg-zinc-800'}`}
|
||||
onClick={() => toggleMode('import')}
|
||||
>
|
||||
Import a repository
|
||||
</Button>
|
||||
<Button
|
||||
variant={!isImportMode ? "default" : "outline"}
|
||||
className={`flex-1 ${!isImportMode ? 'bg-blue-600 hover:bg-blue-700' : 'bg-zinc-900 border-zinc-800 hover:bg-zinc-800'}`}
|
||||
onClick={() => toggleMode('template')}
|
||||
>
|
||||
Start with a template
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Repository list or template list */}
|
||||
{isImportMode ? (
|
||||
<ScrollableRepoList
|
||||
repositories={repositories || []}
|
||||
isLoading={isLoading}
|
||||
onSelect={handleRepoSelect}
|
||||
selectedRepo={selectedRepo}
|
||||
/>
|
||||
) : (
|
||||
<TemplateList onSelect={() => {}} />
|
||||
)}
|
||||
|
||||
{/* Navigation buttons */}
|
||||
<div className="flex justify-end space-x-2 mt-8">
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="text-muted-foreground bg-zinc-900 border-zinc-800 hover:bg-zinc-800"
|
||||
disabled={true} // Disable previous on first step
|
||||
>
|
||||
Previous
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-blue-600 hover:bg-blue-700"
|
||||
onClick={nextStep}
|
||||
disabled={!selectedRepo && isImportMode}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -49,16 +49,16 @@
|
||||
import { Github } from 'lucide-react'
|
||||
|
||||
interface Repository {
|
||||
id: string | number;
|
||||
full_name: string;
|
||||
html_url?: string;
|
||||
id: string | number
|
||||
full_name: string
|
||||
html_url?: string
|
||||
}
|
||||
|
||||
interface ScrollableRepoListProps {
|
||||
repositories: Repository[];
|
||||
isLoading: boolean;
|
||||
onSelect: (repoFullName: string) => void;
|
||||
selectedRepo: string;
|
||||
repositories: Repository[]
|
||||
isLoading: boolean
|
||||
onSelect: (repoFullName: string) => void
|
||||
selectedRepo: string
|
||||
}
|
||||
|
||||
export function ScrollableRepoList({
|
||||
@@ -72,14 +72,30 @@ export function ScrollableRepoList({
|
||||
return (
|
||||
<div className="border border-zinc-800 rounded-md bg-zinc-900 overflow-hidden">
|
||||
<div className="p-6 text-center text-zinc-400">
|
||||
<svg className="animate-spin h-5 w-5 text-zinc-400 mx-auto mb-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
||||
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
<svg
|
||||
className="animate-spin h-5 w-5 text-zinc-400 mx-auto mb-2"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
className="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
strokeWidth="4"
|
||||
></circle>
|
||||
<path
|
||||
className="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
Loading repositories...
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
if (!repositories || repositories.length === 0) {
|
||||
@@ -89,29 +105,31 @@ export function ScrollableRepoList({
|
||||
No repositories found. Make sure your GitHub account is connected.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
// Generate mock repositories if needed for testing
|
||||
const repoList = repositories.length > 0 ? repositories :
|
||||
Array.from({ length: 15 }, (_, i) => ({
|
||||
id: `mock-${i}`,
|
||||
full_name: `git-account/repo-name-${i + 1}`
|
||||
}));
|
||||
const repoList =
|
||||
repositories.length > 0
|
||||
? repositories
|
||||
: Array.from({ length: 15 }, (_, i) => ({
|
||||
id: `mock-${i}`,
|
||||
full_name: `git-account/repo-name-${i + 1}`
|
||||
}))
|
||||
|
||||
return (
|
||||
<div className="border border-zinc-800 rounded-md bg-zinc-900 overflow-hidden">
|
||||
{/* Ensure we have a fixed height container with scrolling */}
|
||||
<div
|
||||
<div
|
||||
className="max-h-60 overflow-y-auto"
|
||||
style={{
|
||||
style={{
|
||||
scrollbarWidth: 'thin',
|
||||
scrollbarColor: '#4b5563 #1f2937'
|
||||
}}
|
||||
>
|
||||
{repoList.map((repo, index) => (
|
||||
<div
|
||||
key={repo.id || index}
|
||||
<div
|
||||
key={repo.id || index}
|
||||
className={`flex items-center p-4 border-b border-zinc-800 last:border-b-0 cursor-pointer hover:bg-zinc-800 transition-colors duration-150 ${
|
||||
selectedRepo === repo.full_name ? 'bg-zinc-800' : ''
|
||||
}`}
|
||||
@@ -121,12 +139,10 @@ export function ScrollableRepoList({
|
||||
<Github className="inline-block h-4 w-4 mr-2 text-zinc-400" />
|
||||
<span>{repo.full_name}</span>
|
||||
</div>
|
||||
<div className="text-sm text-zinc-400">
|
||||
5 minutes ago
|
||||
</div>
|
||||
<div className="text-sm text-zinc-400">5 minutes ago</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -66,18 +66,21 @@
|
||||
import { Box, Layout } from 'lucide-react'
|
||||
|
||||
interface Template {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
icon: React.ReactNode
|
||||
}
|
||||
|
||||
interface TemplateListProps {
|
||||
onSelect: (templateId: string) => void;
|
||||
selectedTemplate?: string;
|
||||
onSelect: (templateId: string) => void
|
||||
selectedTemplate?: string
|
||||
}
|
||||
|
||||
export const TemplateList = ({ onSelect, selectedTemplate }: TemplateListProps) => {
|
||||
export const TemplateList = ({
|
||||
onSelect,
|
||||
selectedTemplate
|
||||
}: TemplateListProps) => {
|
||||
// Mock templates data - in a real app, this would come from an API
|
||||
const templates: Template[] = [
|
||||
{
|
||||
@@ -98,7 +101,7 @@ export const TemplateList = ({ onSelect, selectedTemplate }: TemplateListProps)
|
||||
description: 'Simple static site with HTML, CSS, and JavaScript',
|
||||
icon: <Layout className="h-6 w-6" />
|
||||
}
|
||||
];
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="border border-zinc-800 rounded-md bg-zinc-900 overflow-hidden">
|
||||
@@ -116,11 +119,13 @@ export const TemplateList = ({ onSelect, selectedTemplate }: TemplateListProps)
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="font-medium text-sm">{template.name}</div>
|
||||
<div className="text-xs text-muted-foreground">{template.description}</div>
|
||||
<div className="text-xs text-muted-foreground">
|
||||
{template.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// src/components/onboarding/deploy-step/deploy-step.tsx
|
||||
'use client'
|
||||
|
||||
import { useOnboarding } from '@/components/onboarding/useOnboarding'
|
||||
import { useOnboarding } from '@/components/onboarding/store'
|
||||
import { useWallet } from '@/context/WalletContext'
|
||||
import { useDeployment } from '@/hooks/useDeployment'
|
||||
import { useDirectTemplateDeployment } from '@/hooks/useDirectTemplateDeployment'
|
||||
import { useTemplateDeployment } from '@/hooks/useTemplate'
|
||||
import { Alert, AlertDescription } from '@workspace/ui/components/alert'
|
||||
import { Badge } from '@workspace/ui/components/badge'
|
||||
@@ -44,7 +45,7 @@ export function DeployStep() {
|
||||
useTemplateDeployment()
|
||||
|
||||
// Determine deployment type and get the right deploying state
|
||||
const isTemplateMode = formData.deploymentMode === 'template'
|
||||
const isTemplateMode = formData.template ? true : false
|
||||
const isDeploying = isTemplateMode ? isTemplateDeploying : isRepoDeploying
|
||||
|
||||
// Handle hydration mismatch by waiting for mount
|
||||
@@ -132,11 +133,17 @@ export function DeployStep() {
|
||||
throw new Error('Missing required template deployment data')
|
||||
}
|
||||
|
||||
if (!formData.template.repoFullName) {
|
||||
throw new Error('Template repository information is missing')
|
||||
}
|
||||
|
||||
const config = {
|
||||
template: {
|
||||
...formData.template,
|
||||
id: formData.template?.id || '',
|
||||
icon: formData.template?.icon || ''
|
||||
id: formData.template.id,
|
||||
name: formData.template.name,
|
||||
icon: formData.template.icon || '',
|
||||
repoFullName: formData.template.repoFullName,
|
||||
description: formData.template.description || ''
|
||||
},
|
||||
projectName: formData.projectName,
|
||||
organizationSlug: formData.selectedOrg,
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { useOnboarding } from '../store'
|
||||
|
||||
/**
|
||||
* Final step in the onboarding flow
|
||||
* Displays deployment summary and triggers deployment
|
||||
*
|
||||
* Features:
|
||||
* - Configuration summary
|
||||
* - Repository display
|
||||
* - Deploy action
|
||||
*
|
||||
* @component
|
||||
*/
|
||||
export function DeployStep() {
|
||||
useOnboarding()
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="max-w-2xl mx-auto space-y-8">
|
||||
<div className="flex flex-col items-center justify-center w-full max-w-[445px] mx-auto">
|
||||
<div className="w-full flex flex-col items-center gap-6">
|
||||
{/* Header section */}
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<div className="flex flex-col items-center gap-1">
|
||||
<h2 className="text-2xl font-bold text-foreground">Deploy</h2>
|
||||
<p className="text-base text-muted-foreground text-center">
|
||||
Your deployment is configured and ready to go!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
Content sections will be placed here: 1. Repository info card 2.
|
||||
Configuration summary 3. Deploy button
|
||||
{/* ...content here */}
|
||||
{/* <Deploy /> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
'use client'
|
||||
|
||||
import { create } from 'zustand'
|
||||
import { persist, createJSONStorage } from 'zustand/middleware'
|
||||
import type { OnboardingFormData, Step } from './types'
|
||||
|
||||
/**
|
||||
@@ -31,7 +32,7 @@ export interface OnboardingState {
|
||||
}
|
||||
|
||||
/** Order of steps in the onboarding flow */
|
||||
const STEP_ORDER: Step[] = ['connect', 'configure', 'deploy']
|
||||
const STEP_ORDER: Step[] = ['connect', 'configure', 'deploy', 'success']
|
||||
|
||||
/** Initial form data values */
|
||||
const initialFormData: OnboardingFormData = {
|
||||
@@ -64,25 +65,58 @@ const initialFormData: OnboardingFormData = {
|
||||
* const { currentStep, formData, nextStep } = useOnboarding()
|
||||
* ```
|
||||
*/
|
||||
export const useOnboarding = create<OnboardingState>((set) => ({
|
||||
currentStep: 'connect',
|
||||
formData: initialFormData,
|
||||
setCurrentStep: (step) => set({ currentStep: step }),
|
||||
setFormData: (data) =>
|
||||
set((state) => ({
|
||||
formData: { ...state.formData, ...data }
|
||||
})),
|
||||
nextStep: () =>
|
||||
set((state) => {
|
||||
const currentIndex = STEP_ORDER.indexOf(state.currentStep)
|
||||
const nextStep = STEP_ORDER[currentIndex + 1]
|
||||
return nextStep ? { currentStep: nextStep } : state
|
||||
export const useOnboarding = create<OnboardingState>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
currentStep: 'connect',
|
||||
formData: initialFormData,
|
||||
|
||||
setCurrentStep: (step) => set({ currentStep: step }),
|
||||
|
||||
setFormData: (data) => {
|
||||
set((state) => {
|
||||
const newFormData = { ...state.formData, ...data }
|
||||
|
||||
// Keep organizationSlug and selectedOrg in sync
|
||||
if (data.organizationSlug && !data.selectedOrg) {
|
||||
newFormData.selectedOrg = data.organizationSlug
|
||||
}
|
||||
if (data.selectedOrg && !data.organizationSlug) {
|
||||
newFormData.organizationSlug = data.selectedOrg
|
||||
}
|
||||
|
||||
console.log('Store: Setting form data:', data)
|
||||
console.log('Store: New state:', newFormData)
|
||||
|
||||
return { formData: newFormData }
|
||||
})
|
||||
},
|
||||
|
||||
nextStep: () =>
|
||||
set((state) => {
|
||||
const currentIndex = STEP_ORDER.indexOf(state.currentStep)
|
||||
const nextStep = STEP_ORDER[currentIndex + 1]
|
||||
return nextStep ? { currentStep: nextStep } : state
|
||||
}),
|
||||
|
||||
previousStep: () =>
|
||||
set((state) => {
|
||||
const currentIndex = STEP_ORDER.indexOf(state.currentStep)
|
||||
const previousStep = STEP_ORDER[currentIndex - 1]
|
||||
return previousStep ? { currentStep: previousStep } : state
|
||||
}),
|
||||
|
||||
resetOnboarding: () => {
|
||||
set({ currentStep: 'connect', formData: initialFormData })
|
||||
}
|
||||
}),
|
||||
previousStep: () =>
|
||||
set((state) => {
|
||||
const currentIndex = STEP_ORDER.indexOf(state.currentStep)
|
||||
const previousStep = STEP_ORDER[currentIndex - 1]
|
||||
return previousStep ? { currentStep: previousStep } : state
|
||||
}),
|
||||
resetOnboarding: () => set({ currentStep: 'connect', formData: initialFormData })
|
||||
}))
|
||||
{
|
||||
name: 'laconic-onboarding',
|
||||
storage: createJSONStorage(() => localStorage),
|
||||
// Only persist formData, not currentStep
|
||||
partialize: (state) => ({
|
||||
formData: state.formData
|
||||
})
|
||||
}
|
||||
)
|
||||
)
|
||||
@@ -24,8 +24,8 @@ export function SuccessStep() {
|
||||
const repoName = formData.githubRepo
|
||||
? formData.githubRepo.split('/').pop()
|
||||
: formData.repoName
|
||||
? formData.repoName.split('/').pop()
|
||||
: formData.projectName || 'project'
|
||||
? formData.repoName.split('/').pop()
|
||||
: formData.projectName || 'project'
|
||||
const deploymentUrl = `https://${repoName}.laconic.deploy` // Default deployment URL
|
||||
const projectId = formData.projectId || formData.deploymentId || 'unknown-id' // Use projectId first, fallback to deploymentId
|
||||
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
// src/components/onboarding/useOnboarding.ts
|
||||
import { useState } from 'react'
|
||||
import type {
|
||||
OnboardingFormData} from '@/types'
|
||||
|
||||
// Step type for navigation
|
||||
export type Step = 'connect' | 'configure' | 'deploy' | 'success'
|
||||
|
||||
// Initial form data
|
||||
const initialFormData: OnboardingFormData = {
|
||||
// Step 1: Connect
|
||||
githubRepo: undefined,
|
||||
template: undefined,
|
||||
projectName: undefined,
|
||||
deploymentMode: undefined,
|
||||
|
||||
// Step 2: Configure
|
||||
selectedLrn: undefined,
|
||||
selectedOrg: undefined, // Add this property
|
||||
environmentVariables: [], // Use array type
|
||||
deploymentType: undefined, // Add missing properties
|
||||
deployerCount: undefined,
|
||||
maxPrice: undefined,
|
||||
|
||||
// Step 3: Deploy
|
||||
deploymentId: undefined,
|
||||
repositoryUrl: undefined,
|
||||
deploymentUrl: undefined, // Add missing property
|
||||
projectId: undefined // Add missing property
|
||||
}
|
||||
|
||||
export function useOnboarding() {
|
||||
const [formData, setFormData] = useState<OnboardingFormData>(initialFormData)
|
||||
const [currentStep, setCurrentStep] = useState<Step>('connect')
|
||||
|
||||
// Update form data (partial update)
|
||||
const updateFormData = (updates: Partial<OnboardingFormData>) => {
|
||||
setFormData(prev => ({ ...prev, ...updates }))
|
||||
}
|
||||
|
||||
// Reset form data
|
||||
const resetFormData = () => {
|
||||
setFormData(initialFormData)
|
||||
setCurrentStep('connect')
|
||||
}
|
||||
|
||||
// Step navigation
|
||||
const nextStep = () => {
|
||||
switch (currentStep) {
|
||||
case 'connect':
|
||||
setCurrentStep('configure')
|
||||
break
|
||||
case 'configure':
|
||||
setCurrentStep('deploy')
|
||||
break
|
||||
case 'deploy':
|
||||
setCurrentStep('success')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const previousStep = () => {
|
||||
switch (currentStep) {
|
||||
case 'configure':
|
||||
setCurrentStep('connect')
|
||||
break
|
||||
case 'deploy':
|
||||
setCurrentStep('configure')
|
||||
break
|
||||
case 'success':
|
||||
setCurrentStep('deploy')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Validation helpers
|
||||
const validateStep1 = () => {
|
||||
if (formData.deploymentMode === 'template') {
|
||||
return !!(formData.template && formData.projectName)
|
||||
}
|
||||
return !!formData.githubRepo
|
||||
}
|
||||
|
||||
const validateStep2 = () => {
|
||||
return !!(formData.selectedLrn && formData.selectedOrg)
|
||||
}
|
||||
|
||||
const validateStep3 = () => {
|
||||
return !!formData.deploymentId
|
||||
}
|
||||
|
||||
return {
|
||||
// Data
|
||||
formData,
|
||||
currentStep,
|
||||
|
||||
// Actions
|
||||
setFormData: updateFormData,
|
||||
setCurrentStep,
|
||||
resetFormData,
|
||||
resetOnboarding: resetFormData, // Alias for compatibility
|
||||
nextStep,
|
||||
previousStep,
|
||||
|
||||
// Validation
|
||||
validateStep1,
|
||||
validateStep2,
|
||||
validateStep3,
|
||||
|
||||
// Store-like interface for compatibility
|
||||
getState: () => ({
|
||||
formData,
|
||||
currentStep,
|
||||
nextStep,
|
||||
previousStep,
|
||||
setFormData: updateFormData,
|
||||
resetFormData
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user