From 4b7d3b2b3d971f6f1d8ceb0f00651fc414b9cae0 Mon Sep 17 00:00:00 2001 From: Leon Serfaty G Date: Thu, 17 Jul 2025 10:06:15 +0000 Subject: [PATCH] Updated app --- .idx/icon.png | Bin 0 -> 24667 bytes .modified | 0 docs/blueprint.md | 21 +++++ package-lock.json | 43 ++++++++++ package.json | 1 + src/ai/dev.ts | 6 +- src/ai/flows/classify-complexity.ts | 52 +++++++++++ src/ai/flows/suggest-features.ts | 59 +++++++++++++ src/app/globals.css | 81 ++++++------------ src/app/layout.tsx | 16 ++-- src/app/page.tsx | 16 +++- .../cost-estimator/cost-estimator-form.tsx | 74 ++++++++++++++++ .../cost-estimator/step-1-project-type.tsx | 69 +++++++++++++++ tailwind.config.ts | 2 +- 14 files changed, 376 insertions(+), 64 deletions(-) create mode 100644 .idx/icon.png create mode 100644 .modified create mode 100644 docs/blueprint.md create mode 100644 src/ai/flows/classify-complexity.ts create mode 100644 src/ai/flows/suggest-features.ts create mode 100644 src/components/cost-estimator/cost-estimator-form.tsx create mode 100644 src/components/cost-estimator/step-1-project-type.tsx diff --git a/.idx/icon.png b/.idx/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8860a872d1f74336c5f3171eb39d4d9623e86772 GIT binary patch literal 24667 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 JPDHLkV1l@+2?GEC literal 0 HcmV?d00001 diff --git a/.modified b/.modified new file mode 100644 index 0000000..e69de29 diff --git a/docs/blueprint.md b/docs/blueprint.md new file mode 100644 index 0000000..7455a2a --- /dev/null +++ b/docs/blueprint.md @@ -0,0 +1,21 @@ +# **App Name**: EstimateFlow + +## Core Features: + +- Cost Input Form: Interactive form for clients to input project requirements. +- Admin Configuration: Admin panel for configuring pricing parameters and viewing client inputs. +- WordPress Integration: Ability to embed the cost calculator form directly into WordPress websites. +- AI-Assisted Scope Definition: AI-powered suggestions to guide clients in defining project scope and features by acting like a 'tool' offering project management advise +- Dynamic Cost Calculation: Real-time display of cost estimates based on input parameters. +- Custom Calculation Formulas: Options for agencies to customize the cost calculation formula via the admin panel +- AI Complexity Classification: Automatically classify feature complexity from project descriptions by using a 'tool' powered by LLMs, categorizing them as simple, medium, or complex to refine cost estimates + +## Style Guidelines: + +- Primary color: Strong blue (#2979FF) for a modern and trustworthy feel, drawing inspiration from technology and professionalism. +- Background color: Light grayish-blue (#E0E7FF) to provide a clean, unobtrusive backdrop that complements the primary color. +- Accent color: Purple (#794BC4), an analogous color to blue, to add a touch of sophistication and highlight key actions. +- Font Pairing: 'Space Grotesk' (sans-serif) for headings and 'Inter' (sans-serif) for body text. +- Clean, intuitive layout with a focus on user experience. Form elements should be logically grouped and easy to understand. Model initial layout after provided screenshot. +- Use simple, geometric icons to represent different features and project types. +- Subtle animations to provide feedback and guide the user through the cost estimation process. For instance, highlighting a section of the form when it becomes active, and adding transitions between each step of the process \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 55b1a36..357defa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,6 +38,7 @@ "dotenv": "^16.5.0", "embla-carousel-react": "^8.6.0", "firebase": "^11.9.1", + "framer-motion": "^11.3.12", "genkit": "^1.14.1", "lucide-react": "^0.475.0", "next": "15.3.3", @@ -6213,6 +6214,33 @@ "node": ">= 0.6" } }, + "node_modules/framer-motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "license": "MIT", + "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -7537,6 +7565,21 @@ "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==" }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", diff --git a/package.json b/package.json index ec4e4cb..07387b6 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "dotenv": "^16.5.0", "embla-carousel-react": "^8.6.0", "firebase": "^11.9.1", + "framer-motion": "^11.3.12", "genkit": "^1.14.1", "lucide-react": "^0.475.0", "next": "15.3.3", diff --git a/src/ai/dev.ts b/src/ai/dev.ts index 51e556a..f4b4886 100644 --- a/src/ai/dev.ts +++ b/src/ai/dev.ts @@ -1 +1,5 @@ -// Flows will be imported for their side effects in this file. +import { config } from 'dotenv'; +config(); + +import '@/ai/flows/suggest-features.ts'; +import '@/ai/flows/classify-complexity.ts'; \ No newline at end of file diff --git a/src/ai/flows/classify-complexity.ts b/src/ai/flows/classify-complexity.ts new file mode 100644 index 0000000..98d964d --- /dev/null +++ b/src/ai/flows/classify-complexity.ts @@ -0,0 +1,52 @@ +// This is an autogenerated file from Firebase Studio. +'use server'; + +/** + * @fileOverview This file defines a Genkit flow for classifying the complexity of project features. + * + * - classifyComplexity - An async function that takes a feature description and returns its complexity classification. + * - ClassifyComplexityInput - The input type for the classifyComplexity function. + * - ClassifyComplexityOutput - The output type for the classifyComplexity function. + */ + +import {ai} from '@/ai/genkit'; +import {z} from 'genkit'; + +const ClassifyComplexityInputSchema = z.object({ + featureDescription: z + .string() + .describe('A detailed description of the feature to be classified.'), +}); +export type ClassifyComplexityInput = z.infer; + +const ClassifyComplexityOutputSchema = z.object({ + complexity: z + .enum(['simple', 'medium', 'complex']) + .describe('The complexity classification of the feature.'), +}); +export type ClassifyComplexityOutput = z.infer; + +export async function classifyComplexity( + input: ClassifyComplexityInput +): Promise { + return classifyComplexityFlow(input); +} + +const prompt = ai.definePrompt({ + name: 'classifyComplexityPrompt', + input: {schema: ClassifyComplexityInputSchema}, + output: {schema: ClassifyComplexityOutputSchema}, + prompt: `You are an expert project manager classifying the complexity of software features. Classify the following feature description as either 'simple', 'medium', or 'complex'.\n\nFeature Description: {{{featureDescription}}}\n\nComplexity:`, +}); + +const classifyComplexityFlow = ai.defineFlow( + { + name: 'classifyComplexityFlow', + inputSchema: ClassifyComplexityInputSchema, + outputSchema: ClassifyComplexityOutputSchema, + }, + async input => { + const {output} = await prompt(input); + return output!; + } +); diff --git a/src/ai/flows/suggest-features.ts b/src/ai/flows/suggest-features.ts new file mode 100644 index 0000000..f09fbfc --- /dev/null +++ b/src/ai/flows/suggest-features.ts @@ -0,0 +1,59 @@ +'use server'; + +/** + * @fileOverview AI-powered feature suggestion flow based on project description. + * + * - suggestFeatures - A function that suggests features for a project based on its description. + * - SuggestFeaturesInput - The input type for the suggestFeatures function. + * - SuggestFeaturesOutput - The return type for the suggestFeatures function. + */ + +import {ai} from '@/ai/genkit'; +import {z} from 'genkit'; + +const SuggestFeaturesInputSchema = z.object({ + projectDescription: z + .string() + .describe('A brief description of the digital product or project.'), +}); +export type SuggestFeaturesInput = z.infer; + +const SuggestFeaturesOutputSchema = z.object({ + suggestedFeatures: z + .array(z.string()) + .describe('An array of suggested features for the project.'), + scopeDefinitions: z + .string() + .describe('A paragraph defining the overall scope of the project.'), +}); +export type SuggestFeaturesOutput = z.infer; + +export async function suggestFeatures(input: SuggestFeaturesInput): Promise { + return suggestFeaturesFlow(input); +} + +const prompt = ai.definePrompt({ + name: 'suggestFeaturesPrompt', + input: {schema: SuggestFeaturesInputSchema}, + output: {schema: SuggestFeaturesOutputSchema}, + prompt: `You are an AI assistant helping to define the scope and features of digital projects. + + Based on the following project description, suggest a list of potential features and a paragraph defining the project's scope. + + Project Description: {{{projectDescription}}} + + Format the features as a bulleted list and provide a concise scope definition. + `, +}); + +const suggestFeaturesFlow = ai.defineFlow( + { + name: 'suggestFeaturesFlow', + inputSchema: SuggestFeaturesInputSchema, + outputSchema: SuggestFeaturesOutputSchema, + }, + async input => { + const {output} = await prompt(input); + return output!; + } +); diff --git a/src/app/globals.css b/src/app/globals.css index a8144b6..f3e27f8 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -2,79 +2,50 @@ @tailwind components; @tailwind utilities; -body { - font-family: Arial, Helvetica, sans-serif; -} - @layer base { :root { - --background: 0 0% 100%; - --foreground: 0 0% 3.9%; + --background: 226 100% 94.1%; + --foreground: 222 84% 4.9%; --card: 0 0% 100%; - --card-foreground: 0 0% 3.9%; + --card-foreground: 222 84% 4.9%; --popover: 0 0% 100%; - --popover-foreground: 0 0% 3.9%; - --primary: 0 0% 9%; + --popover-foreground: 222 84% 4.9%; + --primary: 221 100% 58%; --primary-foreground: 0 0% 98%; - --secondary: 0 0% 96.1%; - --secondary-foreground: 0 0% 9%; - --muted: 0 0% 96.1%; - --muted-foreground: 0 0% 45.1%; - --accent: 0 0% 96.1%; - --accent-foreground: 0 0% 9%; + --secondary: 226 40% 90%; + --secondary-foreground: 222 84% 4.9%; + --muted: 226 40% 90%; + --muted-foreground: 222 20% 46.1%; + --accent: 263 47% 53%; + --accent-foreground: 0 0% 98%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; - --border: 0 0% 89.8%; - --input: 0 0% 89.8%; - --ring: 0 0% 3.9%; - --chart-1: 12 76% 61%; - --chart-2: 173 58% 39%; - --chart-3: 197 37% 24%; - --chart-4: 43 74% 66%; - --chart-5: 27 87% 67%; + --border: 226 30% 85%; + --input: 226 30% 85%; + --ring: 221 100% 58%; --radius: 0.5rem; - --sidebar-background: 0 0% 98%; - --sidebar-foreground: 240 5.3% 26.1%; - --sidebar-primary: 240 5.9% 10%; - --sidebar-primary-foreground: 0 0% 98%; - --sidebar-accent: 240 4.8% 95.9%; - --sidebar-accent-foreground: 240 5.9% 10%; - --sidebar-border: 220 13% 91%; - --sidebar-ring: 217.2 91.2% 59.8%; } + .dark { - --background: 0 0% 3.9%; + --background: 222 47% 11%; --foreground: 0 0% 98%; - --card: 0 0% 3.9%; + --card: 222 47% 11%; --card-foreground: 0 0% 98%; - --popover: 0 0% 3.9%; + --popover: 222 47% 11%; --popover-foreground: 0 0% 98%; - --primary: 0 0% 98%; + --primary: 221 100% 58%; --primary-foreground: 0 0% 9%; - --secondary: 0 0% 14.9%; + --secondary: 222 25% 20%; --secondary-foreground: 0 0% 98%; - --muted: 0 0% 14.9%; - --muted-foreground: 0 0% 63.9%; - --accent: 0 0% 14.9%; + --muted: 222 25% 20%; + --muted-foreground: 222 10% 63.9%; + --accent: 263 47% 53%; --accent-foreground: 0 0% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 0 0% 98%; - --border: 0 0% 14.9%; - --input: 0 0% 14.9%; - --ring: 0 0% 83.1%; - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; - --sidebar-background: 240 5.9% 10%; - --sidebar-foreground: 240 4.8% 95.9%; - --sidebar-primary: 224.3 76.3% 48%; - --sidebar-primary-foreground: 0 0% 100%; - --sidebar-accent: 240 3.7% 15.9%; - --sidebar-accent-foreground: 240 4.8% 95.9%; - --sidebar-border: 240 3.7% 15.9%; - --sidebar-ring: 217.2 91.2% 59.8%; + --border: 222 25% 20%; + --input: 222 25% 20%; + --ring: 221 100% 58%; } } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index c81ce2d..c296029 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,9 +1,10 @@ import type {Metadata} from 'next'; import './globals.css'; +import { Toaster } from "@/components/ui/toaster"; export const metadata: Metadata = { - title: 'Firebase Studio App', - description: 'Generated by Firebase Studio', + title: 'EstimateFlow', + description: 'Estimate development costs for your next digital product.', }; export default function RootLayout({ @@ -14,11 +15,14 @@ export default function RootLayout({ return ( - - - + + + - {children} + + {children} + + ); } diff --git a/src/app/page.tsx b/src/app/page.tsx index 6ff5373..e0b8bcb 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,3 +1,17 @@ +import { CostEstimatorForm } from '@/components/cost-estimator/cost-estimator-form'; + export default function Home() { - return <>; + return ( +
+
+

+ EstimateFlow +

+

+ Answer a few questions to get a real-time estimate for your digital project. Let's build something amazing together. +

+
+ +
+ ); } diff --git a/src/components/cost-estimator/cost-estimator-form.tsx b/src/components/cost-estimator/cost-estimator-form.tsx new file mode 100644 index 0000000..9c43a7b --- /dev/null +++ b/src/components/cost-estimator/cost-estimator-form.tsx @@ -0,0 +1,74 @@ +"use client"; + +import React, { useState, useTransition } from 'react'; +import { Step1ProjectType } from './step-1-project-type'; +import { Card, CardContent } from '@/components/ui/card'; +import { AnimatePresence, motion } from 'framer-motion'; + +export type FormData = { + projectType: 'website' | 'mobile-app' | 'platform' | null; + // Add more fields for subsequent steps +}; + +export function CostEstimatorForm() { + const [currentStep, setCurrentStep] = useState(1); + const [formData, setFormData] = useState({ + projectType: null, + }); + const [isPending, startTransition] = useTransition(); + + const handleNextStep = () => { + startTransition(() => { + setCurrentStep((prev) => prev + 1); + }); + }; + + const handleUpdateFormData = (newData: Partial) => { + setFormData((prev) => ({ ...prev, ...newData })); + }; + + const renderStep = () => { + switch (currentStep) { + case 1: + return ( + + ); + case 2: + return ( +
+

Step 2: Define Your Project

+

This is where AI will help you define scope.

+

You selected: {formData.projectType}

+
+ ) + default: + return ( + + ); + } + }; + + return ( + + + + + {renderStep()} + + + + + ); +} diff --git a/src/components/cost-estimator/step-1-project-type.tsx b/src/components/cost-estimator/step-1-project-type.tsx new file mode 100644 index 0000000..9e4e1ff --- /dev/null +++ b/src/components/cost-estimator/step-1-project-type.tsx @@ -0,0 +1,69 @@ +"use client"; + +import type { FormData } from './cost-estimator-form'; +import { Monitor, Smartphone, Layers } from 'lucide-react'; +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; +import React from 'react'; + +type Step1Props = { + onNext: () => void; + onUpdateData: (data: Partial) => void; +}; + +const projectTypes = [ + { + id: 'website', + title: 'Website', + description: 'A responsive and engaging online presence.', + icon: , + }, + { + id: 'mobile-app', + title: 'Mobile App', + description: 'An iOS or Android application for users on the go.', + icon: , + }, + { + id: 'platform', + title: 'Platform', + description: 'A complex system with multiple user types.', + icon: , + }, +]; + +export function Step1ProjectType({ onNext, onUpdateData }: Step1Props) { + const handleSelect = (projectType: 'website' | 'mobile-app' | 'platform') => { + onUpdateData({ projectType }); + onNext(); + }; + + return ( +
+

What are you looking to build?

+

Select a project type to get started.

+
+ {projectTypes.map((type) => ( + handleSelect(type.id as any)} + className="cursor-pointer transition-all duration-300 ease-in-out hover:shadow-accent/20 hover:shadow-lg hover:-translate-y-1 hover:border-primary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2" + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') { + handleSelect(type.id as any); + } + }} + > + +
{type.icon}
+ {type.title} +
+ +

{type.description}

+
+
+ ))} +
+
+ ); +} diff --git a/tailwind.config.ts b/tailwind.config.ts index 4d4a68f..489523e 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -11,7 +11,7 @@ export default { extend: { fontFamily: { body: ['Inter', 'sans-serif'], - headline: ['Inter', 'sans-serif'], + headline: ['"Space Grotesk"', 'sans-serif'], code: ['monospace'], }, colors: {