// Timeline + Contact + Footer const Timeline = ({ lang = "en" }) => { const D = PORTFOLIO_DATA; const bn = lang === "bn"; return ( {/* spine */} {D.experience.map((e, i) => ( {/* node */} {i === 0 && } {e.year} {bn ? e.kindBn : e.kind} {bn ? e.roleBn : e.role} {e.company} {bn ? e.detailBn : e.detail} ))} ); }; const Contact = ({ lang = "en" }) => { const D = PORTFOLIO_DATA; const [form, setForm] = React.useState({ name: "", email: "", service: "", budget: "", message: "" }); const [errors, setErrors] = React.useState({}); const [status, setStatus] = React.useState("idle"); // idle | sending | sent const SERVICES = [ "Website & Webapp Development", "AI Agent & Automation", "Web3 & Blockchain", "MT5 EA & Trading Automation", "Browser Scraping & Data Pipeline", "Infrastructure & DevOps", ]; const BUDGETS = ["< $500", "$500 – $2,000", "$2,000 – $5,000", "$5,000 – $15,000", "$15,000+"]; const validate = () => { const e = {}; if (!form.name.trim()) e.name = "Required"; if (!form.email.trim()) e.email = "Required"; else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) e.email = "Not a valid email"; if (!form.service) e.service = "Please pick a service"; if (!form.message.trim()) e.message = "Tell us about the project"; else if (form.message.trim().length < 12) e.message = "A few more words please"; return e; }; const submit = async (ev) => { ev.preventDefault(); const e = validate(); setErrors(e); if (Object.keys(e).length) return; setStatus("sending"); try { const resp = await fetch("https://formsubmit.co/ajax/khondokartowsif171@gmail.com", { method: "POST", headers: { "Content-Type": "application/json", "Accept": "application/json" }, body: JSON.stringify({ _subject: `New Aura Inquiry — ${form.service}`, _captcha: "false", _template: "table", name: form.name, email: form.email, service: form.service, budget: form.budget || "Not specified", message: form.message, }), }); const data = await resp.json(); if (!data.success) throw new Error("failed"); setStatus("sent"); } catch { setStatus("idle"); setErrors({ message: "Network error — please email us directly at ceo@auraajenticai.cloud" }); } }; const Field = ({ id, label, type = "text", as = "input", placeholder }) => { const Tag = as; const hasErr = errors[id]; return ( {label} {hasErr && {hasErr}} setForm(f => ({ ...f, [id]: ev.target.value }))} placeholder={placeholder} rows={as === "textarea" ? 5 : undefined} style={{ width: "100%", background: "var(--bg-elev)", color: "var(--text)", border: `1px solid ${hasErr ? "var(--danger)" : "var(--line)"}`, borderRadius: 10, padding: "12px 14px", fontSize: 14, fontFamily: "var(--font-sans)", resize: as === "textarea" ? "vertical" : "none", outline: "none", transition: "border 0.15s", }} onFocus={(ev) => ev.target.style.borderColor = hasErr ? "var(--danger)" : "var(--accent)"} onBlur={(ev) => ev.target.style.borderColor = hasErr ? "var(--danger)" : "var(--line)"} /> ); }; const SelectField = ({ id, label, options, required = false }) => { const hasErr = errors[id]; return ( {label} {hasErr && {hasErr}} setForm(f => ({ ...f, [id]: ev.target.value }))} style={{ width: "100%", background: "var(--bg-elev)", color: form[id] ? "var(--text)" : "var(--text-faint)", border: `1px solid ${hasErr ? "var(--danger)" : "var(--line)"}`, borderRadius: 10, padding: "12px 14px", fontSize: 14, fontFamily: "var(--font-sans)", outline: "none", transition: "border 0.15s", cursor: "pointer", }} onFocus={(ev) => ev.target.style.borderColor = hasErr ? "var(--danger)" : "var(--accent)"} onBlur={(ev) => ev.target.style.borderColor = hasErr ? "var(--danger)" : "var(--line)"} > Select… {options.map(o => {o})} ); }; return ( Have a project that needs to actually ship?>} sub="Tell us what you're building — we'll respond within 24 hours with a plan and a quote." /> {/* form */} {status === "sent" ? ( {lang === "en" ? "We'll be in touch!" : "বার্তা পাঠানো হয়েছে!"} {lang === "en" ? "We'll get back to you within 24 hours!" : "আমরা ২৪ ঘণ্টার মধ্যে যোগাযোগ করবো!"} { setForm({ name: "", email: "", service: "", budget: "", message: "" }); setStatus("idle"); }} style={{ marginTop: 20, padding: "8px 16px", background: "transparent", color: "var(--text-dim)", border: "1px solid var(--line)", borderRadius: 8, fontSize: 13, cursor: "pointer", }}>{lang === "en" ? "Send another" : "আবার পাঠান"} ) : ( <> {status === "sending" ? "Sending…" : <>Send message >} > )} {/* meta + chatbot teaser */} Direct {D.brand.email} +{D.brand.whatsapp.replace(/^(\d{3})(\d{4})(\d{6})$/, "$1 $2-$3")} {[ { i: Icons.Github, l: "GitHub", h: D.brand.socials.github }, { i: Icons.LinkedIn, l: "LinkedIn", h: D.brand.socials.linkedin }, { i: Icons.Twitter, l: "Twitter", h: D.brand.socials.twitter }, ].map(({ i: I, l, h }) => ( { ev.currentTarget.style.color = "var(--text)"; ev.currentTarget.style.borderColor = "var(--line-strong)"; }} onMouseLeave={ev => { ev.currentTarget.style.color = "var(--text-dim)"; ev.currentTarget.style.borderColor = "var(--line)"; }} > ))} ); }; const ChatbotWidget = () => null; const Footer = ({ lang = "en" }) => { const D = PORTFOLIO_DATA; const bn = lang === "bn"; return ( ); }; window.Timeline = Timeline; window.Contact = Contact; window.Footer = Footer;
{bn ? e.detailBn : e.detail}
{lang === "en" ? "We'll get back to you within 24 hours!" : "আমরা ২৪ ঘণ্টার মধ্যে যোগাযোগ করবো!"}