this is the 3rd step

This commit is contained in:
Leon Serfaty G
2025-07-17 10:09:34 +00:00
parent 6a6e7841e3
commit 1e109c3af7
3 changed files with 102 additions and 3 deletions
@@ -3,12 +3,14 @@
import React, { useState, useTransition } from 'react';
import { Step1ProjectType } from './step-1-project-type';
import { Step2ServiceType } from './step-2-service-type';
import { Step3ProjectStage } from './step-3-project-stage';
import { Card, CardContent } from '@/components/ui/card';
import { AnimatePresence, motion } from 'framer-motion';
export type FormData = {
projectType: 'website' | 'mobile-app' | 'platform' | null;
serviceType: 'entire-project' | 'development' | 'ui-ux-design' | 'identity-branding' | null;
projectStage: number;
};
export function CostEstimatorForm() {
@@ -16,6 +18,7 @@ export function CostEstimatorForm() {
const [formData, setFormData] = useState<FormData>({
projectType: null,
serviceType: null,
projectStage: 0,
});
const [isPending, startTransition] = useTransition();
@@ -25,6 +28,12 @@ export function CostEstimatorForm() {
});
};
const handlePrevStep = () => {
startTransition(() => {
setCurrentStep((prev) => prev - 1);
});
};
const handleUpdateFormData = (newData: Partial<FormData>) => {
setFormData((prev) => ({ ...prev, ...newData }));
};
@@ -42,7 +51,18 @@ export function CostEstimatorForm() {
return (
<Step2ServiceType
onNext={handleNextStep}
onBack={handlePrevStep}
onUpdateData={handleUpdateFormData}
formData={formData}
/>
);
case 3:
return (
<Step3ProjectStage
onNext={handleNextStep}
onBack={handlePrevStep}
onUpdateData={handleUpdateFormData}
formData={formData}
/>
);
default:
@@ -6,7 +6,9 @@ import React from 'react';
type Step2Props = {
onNext: () => void;
onBack: () => void;
onUpdateData: (data: Partial<FormData>) => void;
formData: FormData;
};
const serviceTypes = [
@@ -28,8 +30,8 @@ const serviceTypes = [
},
];
export function Step2ServiceType({ onNext, onUpdateData }: Step2Props) {
const [selectedService, setSelectedService] = React.useState<string | null>(null);
export function Step2ServiceType({ onNext, onBack, onUpdateData, formData }: Step2Props) {
const [selectedService, setSelectedService] = React.useState<string | null>(formData.serviceType);
const handleSelect = (serviceId: 'entire-project' | 'development' | 'ui-ux-design' | 'identity-branding') => {
setSelectedService(serviceId);
@@ -39,7 +41,7 @@ export function Step2ServiceType({ onNext, onUpdateData }: Step2Props) {
return (
<div className="flex flex-col items-start">
<h2 className="font-headline text-3xl font-bold tracking-tight">Choose Service</h2>
<div className="mt-8 grid w-full grid-cols-1 gap-4">
<div className="mt-8 grid w-full grid-cols-1 gap-4 md:grid-cols-2">
{serviceTypes.map((type) => (
<Button
key={type.id}
@@ -52,7 +54,9 @@ export function Step2ServiceType({ onNext, onUpdateData }: Step2Props) {
))}
</div>
<div className="mt-8 flex w-full items-center justify-between">
<Button variant="ghost" onClick={onBack}>Back</Button>
<div className="flex items-center gap-2">
<div className="w-16 h-2 bg-muted rounded-full" />
<div className="w-16 h-2 bg-primary rounded-full" />
<div className="w-16 h-2 bg-muted rounded-full" />
<div className="w-16 h-2 bg-muted rounded-full" />
@@ -0,0 +1,75 @@
"use client";
import type { FormData } from './cost-estimator-form';
import { Button } from '@/components/ui/button';
import { Slider } from '@/components/ui/slider';
import React, { useState, useMemo } from 'react';
type Step3Props = {
onNext: () => void;
onBack: () => void;
onUpdateData: (data: Partial<FormData>) => void;
formData: FormData;
};
const stageLabels = [
"From scratch", // 0
"Idea & concept", // 10
"Prototype ready", // 20
"Design ready", // 30
"In development", // 40
"MVP ready", // 50
"Live product", // 60
"Re-design", // 70
"Adding features", // 80
"Ongoing support", // 90
];
export function Step3ProjectStage({ onNext, onBack, onUpdateData, formData }: Step3Props) {
const [value, setValue] = useState([formData.projectStage]);
const handleSliderChange = (newValue: number[]) => {
setValue(newValue);
onUpdateData({ projectStage: newValue[0] });
};
const currentLabel = useMemo(() => {
const index = Math.floor(value[0] / 10);
return stageLabels[index];
}, [value]);
return (
<div className="flex flex-col items-start">
<h2 className="font-headline text-3xl font-bold tracking-tight">Choose the stage of your project or let's start from scratch</h2>
<div className="mt-16 w-full">
<div className="flex justify-between items-center mb-4">
<p className="font-medium">{currentLabel}</p>
<p className="text-muted-foreground">{value[0] === 90 ? "90+%" : `${value[0]}%`}</p>
</div>
<Slider
defaultValue={value}
onValueChange={handleSliderChange}
max={90}
step={10}
className="w-full"
/>
<div className="flex justify-between text-xs text-muted-foreground mt-2">
<span>0%</span>
<span>90+%</span>
</div>
</div>
<div className="mt-16 flex w-full items-center justify-between">
<Button variant="ghost" onClick={onBack}>Back</Button>
<div className="flex items-center gap-2">
<div className="w-16 h-2 bg-muted rounded-full" />
<div className="w-16 h-2 bg-muted rounded-full" />
<div className="w-16 h-2 bg-primary rounded-full" />
<div className="w-16 h-2 bg-muted rounded-full" />
</div>
<Button onClick={onNext}>
Next
</Button>
</div>
</div>
);
}