Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/data/case-studies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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.",
Expand Down Expand Up @@ -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.",
Expand Down
11 changes: 10 additions & 1 deletion src/features/contact/contact-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ async function submitContactForm(
return { method: "mailto", mailto: buildMailto(payload) };
}

export function ContactForm() {
export function ContactForm({ prefill }: { prefill?: Partial<ContactFormPayload> | null }) {
const searchParams = useSearchParams();
const [form, setForm] = useState<FormState>(initialState);
const [submitState, setSubmitState] = useState<SubmitState>("idle");
Expand All @@ -93,6 +93,15 @@ export function ContactForm() {
}
}, [serviceParam]);

useEffect(() => {
if (prefill) {
setForm((prev) => ({
...prev,
...prefill,
}));
}
}, [prefill]);

function handleChange(
e: React.ChangeEvent<
HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement
Expand Down
92 changes: 55 additions & 37 deletions src/features/contact/contact-page.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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<Partial<ContactFormPayload> | null>(null);

return (
<>
<PageHeader
Expand All @@ -28,47 +34,59 @@ export function ContactPage() {

<Section bordered muted>
<Container>
<div className="grid gap-16 lg:grid-cols-2">
<FadeIn>
<div>
<Heading as="h2" className="text-2xl">
Prefer to write?
</Heading>
<Text variant="muted" className="mt-3">
Share your project goals, timeline, and constraints. I&apos;ll
let you know if we&apos;re a good fit — honestly and quickly.
</Text>
<div className="grid gap-12 lg:grid-cols-2 lg:items-start">
{/* Interactive Scope Calculator */}
<div className="space-y-8">
<FadeIn>
<ProjectEstimator onApply={(data) => setPrefill(data)} />
</FadeIn>

<div className="mt-8 space-y-4">
<div>
<p className="text-sm font-medium">Email</p>
<a
href={`mailto:${siteConfig.author.email}`}
className="text-muted-foreground mt-1 text-sm underline-offset-4 transition-colors hover:text-foreground hover:underline"
>
{siteConfig.author.email}
</a>
</div>
<div>
<p className="text-sm font-medium">Response time</p>
<p className="text-muted-foreground mt-1 text-sm">
Within one business day
</p>
</div>
<div>
<p className="text-sm font-medium">Time zones</p>
<p className="text-muted-foreground mt-1 text-sm">
US, Canada, UK, Europe, Australia
</p>
{/* Minimalist direct email backup info */}
<FadeIn delay={0.05}>
<div className="rounded-xl border border-border bg-card/10 p-6 space-y-4">
<Heading as="h4" className="text-sm font-semibold uppercase tracking-wider text-muted-foreground">
Direct Correspondence
</Heading>
<div className="grid grid-cols-2 gap-4 text-xs md:text-sm">
<div>
<p className="font-semibold text-foreground">Email</p>
<a
href={`mailto:${siteConfig.author.email}`}
className="text-muted-foreground mt-0.5 block underline-offset-4 hover:text-foreground hover:underline"
>
{siteConfig.author.email}
</a>
</div>
<div>
<p className="font-semibold text-foreground">Time Zones</p>
<p className="text-muted-foreground mt-0.5">US, EU, UK, AU & India</p>
</div>
</div>
</div>
</div>
</FadeIn>
</FadeIn>
</div>

{/* Contact Form */}
<FadeIn delay={0.08}>
<Suspense fallback={<div className="h-64 flex items-center justify-center text-sm text-muted-foreground">Loading contact form...</div>}>
<ContactForm />
</Suspense>
<div className="rounded-xl border border-border bg-card p-6 md:p-8">
<div className="mb-6">
<Heading as="h3" className="text-xl font-bold tracking-tight">
Prefer to write?
</Heading>
<Text variant="small" className="mt-1">
Share your requirements directly below. I will analyze and respond in 24 hours.
</Text>
</div>
<Suspense
fallback={
<div className="h-64 flex items-center justify-center text-sm text-muted-foreground">
Loading contact form...
</div>
}
>
<ContactForm prefill={prefill} />
</Suspense>
</div>
</FadeIn>
</div>
</Container>
Expand Down
Loading
Loading