From c115b8ec65b5c827592f5a4ee8bf9e901c8d1273 Mon Sep 17 00:00:00 2001 From: kailash-dev Date: Sat, 18 Jul 2026 00:11:04 +0530 Subject: [PATCH] feat: implement lead calculator, architecture explorer, and live status indicators --- src/data/case-studies.ts | 15 +- src/features/contact/contact-form.tsx | 11 +- src/features/contact/contact-page.tsx | 92 ++++---- src/features/contact/project-estimator.tsx | 225 +++++++++++++++++++ src/features/work/case-study-page.tsx | 238 ++++++++++++++++++++- src/features/work/work-page.tsx | 30 ++- src/types/index.ts | 1 + 7 files changed, 562 insertions(+), 50 deletions(-) create mode 100644 src/features/contact/project-estimator.tsx diff --git a/src/data/case-studies.ts b/src/data/case-studies.ts index ce16951..1ad8cb7 100644 --- a/src/data/case-studies.ts +++ b/src/data/case-studies.ts @@ -8,6 +8,7 @@ export const caseStudies: CaseStudy[] = [ category: "Compliance Marketplace", visual: "portal", image: withBasePath("/images/projects/safework-global.jpg"), + status: "Live hiring in 50+ countries", client: "SafeWork Global", liveUrl: "https://safeworkglobal.com", year: "2025", @@ -59,6 +60,7 @@ export const caseStudies: CaseStudy[] = [ category: "B2B Connector · Integration Plugin", visual: "portal", image: withBasePath("/images/projects/whatsapp-profile-sync.png"), + status: "Self-hosted & Active", year: "2026", summary: "A self-hosted, config-driven B2B integration plugin (SyncFlow) that turns structured WhatsApp messages and attachments into database profile upserts. Connect with me for your organization-level setup.", @@ -108,6 +110,7 @@ export const caseStudies: CaseStudy[] = [ category: "Founder Product · AI Resume Optimization", visual: "ai", image: withBasePath("/images/projects/jobfit-ai.png"), + status: "Active SaaS workspace", year: "2026", summary: "An AI-powered resume optimization workspace (JobFit AI) that reviews a candidate's existing resume against a target Job Description (JD) to identify missing skills, highlight experience gaps, and suggest keyword improvements.", @@ -152,9 +155,10 @@ export const caseStudies: CaseStudy[] = [ { slug: "vyaparpost", title: "VyaparPost", - category: "Founder Product · SaaS", + category: "Founder Product · Invoicing SaaS", visual: "design", image: withBasePath("/images/projects/vyaparpost.jpg"), + status: "Uptime: 99.9% in Production", liveUrl: "https://vyaparpost.in", year: "2025", summary: @@ -202,9 +206,10 @@ export const caseStudies: CaseStudy[] = [ { slug: "vendor-infra", title: "Vendor Infra", - category: "B2B Industry Platform", + category: "Search Portal · Infrastructure B2B", visual: "portal", image: withBasePath("/images/projects/vendor-infra.jpg"), + status: "Active B2B search engine", client: "Vendor Infra", liveUrl: "https://vendorinfra.com", year: "2024–2025", @@ -263,6 +268,7 @@ export const caseStudies: CaseStudy[] = [ category: "IoT · Multi-client Dashboard", visual: "iot", image: withBasePath("/images/projects/solar-monitoring.png"), + status: "Active live telemetry", year: "2020–Present", summary: "Multi-client IoT dashboard for solar monitoring — real-time graphs, reusable chart systems, and performance-tuned visualization for operators who need clarity at a glance.", @@ -312,6 +318,7 @@ export const caseStudies: CaseStudy[] = [ category: "Creative Tooling", visual: "design", image: withBasePath("/images/projects/graphic-design-platform.png"), + status: "Active editor workspace", year: "2021–Present", summary: "A Canva-like design product with SVG editing, brand kits, templates, zoomable canvas, and separate portals for admins and designers.", @@ -368,6 +375,7 @@ export const caseStudies: CaseStudy[] = [ category: "B2B · Web & Mobile", visual: "commerce", image: withBasePath("/images/projects/digital-invoice.png"), + status: "Active invoicing system", year: "2021–Present", summary: "End-to-end invoicing and catalog product across web and mobile — with JWT sessions, Redis-backed state, and scalable frontend architecture.", @@ -424,6 +432,7 @@ export const caseStudies: CaseStudy[] = [ category: "Community Platform", visual: "mobile", image: withBasePath("/images/projects/vipra-community.png"), + status: "Active community hub", year: "2022–Present", summary: "Community platform with matrimony, business directory, and jobs — used by real people for real life outcomes.", @@ -470,6 +479,7 @@ export const caseStudies: CaseStudy[] = [ category: "IoT · Device Experience", visual: "iot", image: withBasePath("/images/projects/nstream-connect.png"), + status: "Active on transit hardware", year: "2019–2020", summary: "IoT entertainment device experience for travelers — production frontend, media playback, and tight collaboration with embedded hardware.", @@ -519,6 +529,7 @@ export const caseStudies: CaseStudy[] = [ category: "Embedded · Monitoring", visual: "iot", image: withBasePath("/images/projects/raspberry-pi-monitoring.png"), + status: "Active field video capture", year: "2019–2020", summary: "Camera-based monitoring on Raspberry Pi Zero — MotionEye integration, camera modules, and Raspberry Pi OS customization for a reliable field device.", diff --git a/src/features/contact/contact-form.tsx b/src/features/contact/contact-form.tsx index fd1f181..7e1fdf8 100644 --- a/src/features/contact/contact-form.tsx +++ b/src/features/contact/contact-form.tsx @@ -76,7 +76,7 @@ async function submitContactForm( return { method: "mailto", mailto: buildMailto(payload) }; } -export function ContactForm() { +export function ContactForm({ prefill }: { prefill?: Partial | null }) { const searchParams = useSearchParams(); const [form, setForm] = useState(initialState); const [submitState, setSubmitState] = useState("idle"); @@ -93,6 +93,15 @@ export function ContactForm() { } }, [serviceParam]); + useEffect(() => { + if (prefill) { + setForm((prev) => ({ + ...prev, + ...prefill, + })); + } + }, [prefill]); + function handleChange( e: React.ChangeEvent< HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement diff --git a/src/features/contact/contact-page.tsx b/src/features/contact/contact-page.tsx index b209454..408647c 100644 --- a/src/features/contact/contact-page.tsx +++ b/src/features/contact/contact-page.tsx @@ -1,4 +1,6 @@ -import { Suspense } from "react"; +"use client"; + +import { useState, Suspense } from "react"; import { CalendlyEmbed } from "@/components/common/calendly-embed"; import { Container } from "@/components/common/container"; import { FadeIn } from "@/components/common/fade-in"; @@ -9,8 +11,12 @@ import { PageHeader } from "@/components/layout/page-header"; import { siteConfig } from "@/config/site"; import { faqItems } from "@/data"; import { ContactForm } from "./contact-form"; +import { ProjectEstimator } from "./project-estimator"; +import type { ContactFormPayload } from "@/types"; export function ContactPage() { + const [prefill, setPrefill] = useState | null>(null); + return ( <> -
- -
- - Prefer to write? - - - Share your project goals, timeline, and constraints. I'll - let you know if we're a good fit — honestly and quickly. - +
+ {/* Interactive Scope Calculator */} +
+ + setPrefill(data)} /> + -
- -
-

Response time

-

- Within one business day -

-
-
-

Time zones

-

- US, Canada, UK, Europe, Australia -

+ {/* Minimalist direct email backup info */} + +
+ + Direct Correspondence + +
+ +
+

Time Zones

+

US, EU, UK, AU & India

+
-
- + +
+ {/* Contact Form */} - Loading contact form...
}> - - +
+
+ + Prefer to write? + + + Share your requirements directly below. I will analyze and respond in 24 hours. + +
+ + Loading contact form... +
+ } + > + + +
diff --git a/src/features/contact/project-estimator.tsx b/src/features/contact/project-estimator.tsx new file mode 100644 index 0000000..d07e5db --- /dev/null +++ b/src/features/contact/project-estimator.tsx @@ -0,0 +1,225 @@ +"use client"; + +import { useState, useMemo } from "react"; +import { ArrowRight, Check, Sparkles, Clock, Layers } from "lucide-react"; +import { Heading, Text } from "@/components/common/typography"; +import { cn } from "@/lib/utils"; +import type { ContactFormPayload } from "@/types"; + +type ProjectEstimatorProps = { + onApply: (data: Partial) => void; +}; + +type ProductType = "SaaS" | "Mobile" | "IoT"; +type ProjectStage = "MVP" | "Scale" | "Integration"; + +export function ProjectEstimator({ onApply }: ProjectEstimatorProps) { + const [productType, setProductType] = useState("SaaS"); + const [stage, setStage] = useState("MVP"); + const [hasApplied, setHasApplied] = useState(false); + + const estimate = useMemo(() => { + let duration = "6–8 weeks"; + let tech = "Next.js, Node.js, PostgreSQL, Tailwind"; + let savings = "20+ hours of manual operations / week"; + let budget = "$25k – $50k"; + let timeline = "1–3 months"; + + if (productType === "SaaS") { + if (stage === "MVP") { + duration = "6–8 weeks"; + tech = "Next.js, Node.js, PostgreSQL, Tailwind"; + savings = "20+ operational hours saved / week"; + budget = "$10k – $25k"; + timeline = "1–3 months"; + } else if (stage === "Scale") { + duration = "8–12 weeks"; + tech = "Next.js, Redis cache, PostgreSQL indexing, CI/CD"; + savings = "15+ developer pipeline hours saved / week"; + budget = "$25k – $50k"; + timeline = "1–3 months"; + } else { + duration = "4–6 weeks"; + tech = "Node.js, REST APIs, Webhook integrations"; + savings = "30+ copy-paste database entries automated / week"; + budget = "Under $10k"; + timeline = "ASAP"; + } + } else if (productType === "Mobile") { + if (stage === "MVP") { + duration = "8–10 weeks"; + tech = "React Native, Node.js API, JWT Session, Expo"; + savings = "Single codebase targeting iOS & Android natively"; + budget = "$25k – $50k"; + timeline = "3–6 months"; + } else if (stage === "Scale") { + duration = "12–16 weeks"; + tech = "React Native, Redis session store, API optimization"; + savings = "99.9% mobile sync reliability SLA"; + budget = "$50k+"; + timeline = "3–6 months"; + } else { + duration = "4–8 weeks"; + tech = "Mobile push notifications, deep links, analytics"; + savings = "Zero manual user-notifying overhead"; + budget = "$10k – $25k"; + timeline = "1–3 months"; + } + } else if (productType === "IoT") { + if (stage === "MVP") { + duration = "10–12 weeks"; + tech = "Raspberry Pi OS, C/C++, Webhook gateway, Cloud portal"; + savings = "Field-ready custom image ready for manufacturing"; + budget = "$25k – $50k"; + timeline = "3–6 months"; + } else if (stage === "Scale") { + duration = "14–18 weeks"; + tech = "Embedded OS configurations, camera analytics, telemetry logs"; + savings = "Continuous live status and failure-recovery cycles"; + budget = "$50k+"; + timeline = "3–6 months"; + } else { + duration = "6–8 weeks"; + tech = "MotionEye captures, custom OS scripts, shell config"; + savings = "Zero manual site-logging overhead for field teams"; + budget = "$10k – $25k"; + timeline = "1–3 months"; + } + } + + return { duration, tech, savings, budget, timeline }; + }, [productType, stage]); + + const handleApply = () => { + onApply({ + budget: estimate.budget, + timeline: estimate.timeline, + message: `Hi Kailash,\n\nI used your Project Estimator to scope our work:\n- Product: ${productType} (${stage})\n- Projected Timeline: ${estimate.duration}\n- Recommended Stack: ${estimate.tech}\n\nLet's schedule a call to review details.`, + }); + setHasApplied(true); + setTimeout(() => setHasApplied(false), 3000); + }; + + return ( +
+ {/* Decorative Grid Pattern */} +
+ +
+
+ + + Project Estimator + + + Toggle your scope preferences to estimate timeline and stack parameters. + +
+ + {/* Product Type Toggle */} +
+ +
+ {(["SaaS", "Mobile", "IoT"] as ProductType[]).map((t) => ( + + ))} +
+
+ + {/* Project Stage Toggle */} +
+ +
+ {(["MVP", "Scale", "Integration"] as ProjectStage[]).map((s) => ( + + ))} +
+
+ + {/* Calculations Results card */} +
+
+ + + +
+ + Projected Duration + + {estimate.duration} +
+
+ +
+ + + +
+ + Recommended Architecture + + {estimate.tech} +
+
+ +
+ + Business Outcome Focus + + + {estimate.savings} + +
+
+ + +
+
+ ); +} diff --git a/src/features/work/case-study-page.tsx b/src/features/work/case-study-page.tsx index 6e1ba40..7aa207e 100644 --- a/src/features/work/case-study-page.tsx +++ b/src/features/work/case-study-page.tsx @@ -2,8 +2,8 @@ import Link from "next/link"; import Image from "next/image"; -import { useState } from "react"; -import { ArrowUpRight, X } from "lucide-react"; +import { useState, useMemo } from "react"; +import { ArrowUpRight, X, ArrowRight, Cpu, Database, Server, Globe } from "lucide-react"; import { notFound } from "next/navigation"; import { Badge } from "@/components/common/badge"; @@ -17,11 +17,228 @@ import { Button } from "@/components/ui/button"; import { cta } from "@/constants"; import { getCaseStudyBySlug } from "@/data"; import { createCaseStudySchema } from "@/lib/seo"; +import { cn } from "@/lib/utils"; +import type { CaseStudy } from "@/types"; -type CaseStudyPageProps = { - slug: string; +type FlowNode = { + id: string; + label: string; + description: string; + tech: string[]; }; +const getFlowNodes = (study: CaseStudy): FlowNode[] => { + const tech = study.tech; + const isIot = study.visual === "iot" || study.category.toLowerCase().includes("iot"); + const isDesign = study.visual === "design"; + const isMobile = study.visual === "mobile"; + + if (isIot) { + return [ + { + id: "device", + label: "Field Device / OS", + description: "Raspberry Pi or telemetry sensor node running tailored Linux configurations.", + tech: tech.filter(t => ["Raspberry Pi Zero", "Raspberry Pi OS", "Embedded Linux", "Hardware", "IoT", "Embedded OS"].includes(t)), + }, + { + id: "ingestion", + label: "Ingestion Engine", + description: "MotionEye or telemetry service parsing inputs, handling camera capture, and buffering logs.", + tech: tech.filter(t => ["MotionEye", "Camera module", "RxJS", "IoT telemetry", "Charting"].includes(t)), + }, + { + id: "transport", + label: "State webhooks / APIs", + description: "Deterministic JSON/YAML webhooks normalizing inputs and routing payloads securely.", + tech: tech.filter(t => ["Node.js", "TypeScript", "REST APIs", "YAML", "Webhook"].includes(t)), + }, + { + id: "destination", + label: "B2B Cloud Portal", + description: "Multi-tenant dashboard rendering status, real-time analytics graphs, and alerts.", + tech: tech.filter(t => ["Angular", "React", "PostgreSQL", "Cloud deployment"].includes(t)), + }, + ].filter(n => n.tech.length > 0 || n.id === "device" || n.id === "destination"); + } + + if (isDesign) { + return [ + { + id: "editor", + label: "Canvas Editor Engine", + description: "Fabric.js canvas wrapper managing canvas scaling, SVG rendering, and layer state.", + tech: tech.filter(t => ["Fabric.js", "SVG", "Canvas editing"].includes(t)), + }, + { + id: "serialization", + label: "State JSON Serializer", + description: "Normalizing designs as JSON payloads for secure template storage and reload logic.", + tech: tech.filter(t => ["JSON persistence", "Brand systems"].includes(t)), + }, + { + id: "portal", + label: "Angular Shell UI", + description: "Role-separated application interfaces for designers and operators with authentication.", + tech: tech.filter(t => ["Angular", "Angular Material", "TypeScript", "Role-based portals"].includes(t)), + }, + ].filter(n => n.tech.length > 0 || n.id === "editor" || n.id === "portal"); + } + + if (isMobile) { + return [ + { + id: "client", + label: "React Native Client", + description: "Native mobile application client presenting community modules and profile details.", + tech: tech.filter(t => ["React Native", "Auth & sessions"].includes(t)), + }, + { + id: "auth", + label: "JWT Auth / REST APIs", + description: "Secure gateway verification, route guards, and payload validation layers.", + tech: tech.filter(t => ["JWT", "REST APIs", "Node.js"].includes(t)), + }, + { + id: "storage", + label: "Backend & Database", + description: "Relational database model holding profile, business, and job listings.", + tech: tech.filter(t => ["Node.js", "PostgreSQL", "Redis"].includes(t)), + }, + ].filter(n => n.tech.length > 0 || n.id === "client" || n.id === "storage"); + } + + // Default SaaS / Web application flow + return [ + { + id: "client", + label: "Client Web / UI", + description: "Fast-loading React/Next.js/Angular application layer focusing on premium UX and layouts.", + tech: tech.filter(t => ["React", "TypeScript", "Angular", "Vanilla HTML/CSS/JS"].includes(t)), + }, + { + id: "server", + label: "Node / Next.js Server", + description: "Server-side business logic, security middleware, and third-party gateway integrations.", + tech: tech.filter(t => ["Node.js", "Node", "TypeScript", "YAML template parser"].includes(t)), + }, + { + id: "cache", + label: "Redis Cache / Webhooks", + description: "Webhook template parsing, in-memory event queues, and allowlisted sender traces.", + tech: tech.filter(t => ["Redis", "Webhook architecture", "File uploads & API syncing"].includes(t)), + }, + { + id: "storage", + label: "PostgreSQL Database", + description: "Secure relational storage holding transactional accounts, verification states, and tables.", + tech: tech.filter(t => ["PostgreSQL", "Payments & escrow"].includes(t)), + }, + ].filter(n => n.tech.length > 0 || n.id === "client" || n.id === "storage"); +}; + +function ArchitectureExplorer({ study }: { study: CaseStudy }) { + const nodes = useMemo(() => getFlowNodes(study), [study]); + const [activeNodeId, setActiveNodeId] = useState(nodes[0]?.id || ""); + + const activeNode = useMemo(() => { + return nodes.find(n => n.id === activeNodeId) || nodes[0]; + }, [nodes, activeNodeId]); + + if (nodes.length === 0) return null; + + const getIcon = (id: string) => { + switch (id) { + case "device": return ; + case "editor": return ; + case "client": return ; + case "ingestion": return ; + case "transport": return ; + case "auth": return ; + case "server": return ; + case "cache": return ; + case "storage": return ; + case "destination": return ; + case "portal": return ; + default: return ; + } + }; + + return ( +
+ {/* Node blocks row */} +
+ {nodes.map((node, idx) => { + const isActive = node.id === activeNodeId; + return ( +
+ + + {idx < nodes.length - 1 && ( +
+ +
+ )} +
+ ); + })} +
+ + {/* Detail card of active node */} + {activeNode && ( +
+
+

+ + {getIcon(activeNode.id)} + + {activeNode.label} +

+ + Component Node + +
+ +

+ {activeNode.description} +

+ + {activeNode.tech.length > 0 && ( +
+ + Technologies Involved: + +
+ {activeNode.tech.map(t => ( + + {t} + + ))} +
+
+ )} +
+ )} +
+ ); +} + function DetailBlock({ title, children, @@ -41,7 +258,7 @@ function DetailBlock({ ); } -export function CaseStudyPage({ slug }: CaseStudyPageProps) { +export function CaseStudyPage({ slug }: { slug: string }) { const [isZoomed, setIsZoomed] = useState(false); const study = getCaseStudyBySlug(slug); @@ -137,9 +354,18 @@ export function CaseStudyPage({ slug }: CaseStudyPageProps) { - + {study.architecture} + + {/* Visual Architecture Explorer */} +
+

+ Interactive System Architecture Flow +

+ + +
diff --git a/src/features/work/work-page.tsx b/src/features/work/work-page.tsx index d3640cd..d6f20c9 100644 --- a/src/features/work/work-page.tsx +++ b/src/features/work/work-page.tsx @@ -102,8 +102,19 @@ export function BentoCard({ study, className, isWide = false, isFull = false }: isFull ? "lg:w-2/5" : "lg:w-1/2" )}>
-
- +
+
+ + {study.status && ( + + + + + + {study.status} + + )} +
{study.year && ( {study.year} )} @@ -192,8 +203,19 @@ export function BentoCard({ study, className, isWide = false, isFull = false }:
-
- +
+
+ + {study.status && ( + + + + + + {study.status} + + )} +
{study.year && ( {study.year} )} diff --git a/src/types/index.ts b/src/types/index.ts index 0d03ab0..a6f48bc 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -36,6 +36,7 @@ export type CaseStudy = { /** client = built for a client; founder = own product/idea */ engagement?: "client" | "founder" | "employment"; year?: string; + status?: string; }; export type ExperienceRole = {