From 95b3ea43836818a3d20c31f0fa1217c0409ecb91 Mon Sep 17 00:00:00 2001 From: Thimon Date: Sun, 26 Oct 2025 17:52:17 +0100 Subject: [PATCH] Minecraft & VPS added --- web/app/contact/page.tsx | 242 ++++++++--- web/app/minecraft/DeployWizard.tsx | 385 +++++++++++++++++ web/app/minecraft/page.tsx | 328 +++++++++++++++ web/app/page.tsx | 198 ++++++--- web/app/pricing/PricingConfigurator.tsx | 358 ++++++++++++++++ web/app/pricing/page.tsx | 260 +++++++++--- web/app/services/page.tsx | 468 +++++++++++++++++---- web/app/vps/VPSDeployWizard.tsx | 410 ++++++++++++++++++ web/app/vps/page.tsx | 305 ++++++++++++++ web/components/Footer.tsx | 2 +- web/components/Header.tsx | 2 + web/components/pricing/ComparisonTable.tsx | 18 +- web/components/pricing/FAQ.tsx | 98 ++++- web/components/pricing/Guarantee.tsx | 4 +- web/components/pricing/PlanCard.tsx | 4 +- web/components/pricing/PlanRecommender.tsx | 2 +- web/free/page.tsx | 254 ----------- web/lib/services.ts | 413 ++++++++++-------- 18 files changed, 2999 insertions(+), 752 deletions(-) create mode 100644 web/app/minecraft/DeployWizard.tsx create mode 100644 web/app/minecraft/page.tsx create mode 100644 web/app/pricing/PricingConfigurator.tsx create mode 100644 web/app/vps/VPSDeployWizard.tsx create mode 100644 web/app/vps/page.tsx delete mode 100644 web/free/page.tsx diff --git a/web/app/contact/page.tsx b/web/app/contact/page.tsx index 0984eec..2615047 100644 --- a/web/app/contact/page.tsx +++ b/web/app/contact/page.tsx @@ -19,7 +19,33 @@ export default function ContactPage() { function RequestForm() { const router = useRouter(); const searchParams = useSearchParams(); - const prefillType = searchParams.get("type") as RequestType | null; + + // Accept both ?type= and ?plan= to allow links from multiple pages + const rawType = (searchParams.get("type") || searchParams.get("plan")) as string | null; + + type RequestType = + | "recommendation" + | "vps" + | "website-care" + | "development" + | "minecraft-hosting" + | "plugin" + | "support" + | "partnership"; + + const isRequestType = (v: any): v is RequestType => + [ + "recommendation", + "vps", + "website-care", + "development", + "minecraft-hosting", + "plugin", + "support", + "partnership", + ].includes(v); + + const prefillType: RequestType | "" = rawType && isRequestType(rawType) ? rawType : ""; const [step, setStep] = useState(1); const [loading, setLoading] = useState(false); @@ -30,29 +56,46 @@ function RequestForm() { domain: "", company: "", message: "", - hosting: "", + hosting: "", // reused for Minecraft edition (Java/Bedrock/etc.) concern: "", }); - type RequestType = - | "audit" - | "consultation" - | "support" - | "tool" - | "partnership"; - const requestTypes: { id: RequestType; label: string; desc: string; icon: string }[] = [ { - id: "audit", - label: "Free Audit", - desc: "Request a free website, DNS or performance check.", - icon: "🧠", + id: "recommendation", + label: "Get My Recommendation", + desc: "Tell us about your stack/server. We’ll propose the right plan and next steps.", + icon: "🧭", }, { - id: "consultation", - label: "Consultation / Quote", - desc: "Discuss a project, hosting setup, or optimization.", - icon: "āš™ļø", + id: "vps", + label: "Managed VPS Hosting", + desc: "Hardened, monitored VPS with restore-tested backups.", + icon: "šŸ–„ļø", + }, + { + id: "website-care", + label: "Managed Website Hosting & Care", + desc: "Updates, uptime, security checks, monthly restore tests.", + icon: "šŸ›”ļø", + }, + { + id: "development", + label: "Website Development", + desc: "Fast, SEO-ready Next.js site with deployment.", + icon: "⚔", + }, + { + id: "minecraft-hosting", + label: "Managed Minecraft Hosting", + desc: "Lag-free server on a hardened VPS with backups and tuning.", + icon: "ā›ļø", + }, + { + id: "plugin", + label: "Minecraft Plugin Development", + desc: "Custom Paper/Spigot plugins with tests and docs.", + icon: "šŸ”Œ", }, { id: "support", @@ -60,12 +103,6 @@ function RequestForm() { desc: "Report an issue or request hands-on help.", icon: "šŸ› ļø", }, - { - id: "tool", - label: "Tool Follow-Up", - desc: "Continue from one of our free tools or reports.", - icon: "šŸ“Š", - }, { id: "partnership", label: "Partnership / Collaboration", @@ -107,20 +144,61 @@ function RequestForm() { } }; + const submitLabel = + form.type === "recommendation" + ? "Get My Recommendation" + : form.type === "plugin" + ? "Request Plugin Quote" + : form.type === "minecraft-hosting" + ? "Launch My Minecraft Server" + : form.type === "development" + ? "Request Website Proposal" + : form.type === "vps" || form.type === "website-care" + ? "Send Technical Details" + : "Submit Request"; + + const showDomainInput = + form.type === "recommendation" || + form.type === "vps" || + form.type === "website-care" || + form.type === "development" || + form.type === "support"; + + const showMinecraftEdition = + form.type === "minecraft-hosting" || form.type === "plugin"; + return (
+ {/* --- HERO --- */}

- Start a Request + Talk to an Engineer

- Choose what you’d like to do — audits, consultations, or support. - We’ll guide you through the right steps and get back within one business day. + Tell us about your stack or server. We’ll recommend a plan and outline next steps—no lock-in.

+ + {/* Trust microcopy */} +
+ {[ + { t: "Mutual NDA", s: "Available on request" }, + { t: "Least-Privilege Access", s: "Credentials scoped to the task" }, + { t: "Month-to-Month", s: "30-day cancel policy" }, + ].map((item) => ( +
+
{item.t}
+
{item.s}
+
+ ))} +
+ {/* --- FORM --- */}
{step === 1 && ( @@ -132,7 +210,7 @@ function RequestForm() { transition={{ duration: 0.3 }} >

- What kind of request do you have? + What do you need help with?

{requestTypes.map((t) => ( @@ -200,41 +278,66 @@ function RequestForm() { />
- {(form.type === "audit" || form.type === "consultation") && ( - <> -
- - -
+ {showDomainInput && ( +
+ + +
+ )} -
- - -
- + {/* Concern selector for scoping */} + {(form.type !== "" && form.type !== "partnership") && ( +
+ + +
+ )} + + {/* Minecraft edition for hosting/plugin */} + {showMinecraftEdition && ( +
+ + +
)}
@@ -246,7 +349,15 @@ function RequestForm() { rows={4} value={form.message} onChange={handleChange} - placeholder="Describe your request..." + placeholder={ + form.type === "plugin" + ? "Describe the plugin features, commands/permissions, and any existing code…" + : form.type === "development" + ? "Describe pages/sections, brand goals, timeline, and examples you like…" + : form.type === "minecraft-hosting" + ? "Player count, peak times, current host/specs, and performance issues…" + : "Describe your request..." + } className="w-full rounded-lg border border-neutral-300 dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" />
@@ -265,9 +376,14 @@ function RequestForm() { disabled={loading} className="rounded-lg bg-gradient-to-r from-blue-600 via-purple-600 to-blue-600 text-white font-medium px-6 py-2 hover:opacity-90 transition" > - {loading ? "Submitting..." : "Submit Request"} + {loading ? "Submitting..." : submitLabel} + + {/* GDPR-friendly footer note */} +

+ We use your details only to respond to your request. No unsolicited marketing. EU/GDPR-friendly. +

)}
diff --git a/web/app/minecraft/DeployWizard.tsx b/web/app/minecraft/DeployWizard.tsx new file mode 100644 index 0000000..6aa371b --- /dev/null +++ b/web/app/minecraft/DeployWizard.tsx @@ -0,0 +1,385 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import { AnimatePresence, motion } from "framer-motion"; +import { toast } from "sonner"; + +type PlanId = "starter" | "pro" | "network"; +type Edition = "java" | "bedrock" | "modded"; +type ModLoader = "paper" | "spigot" | "velocity" | "forge" | "fabric" | ""; +type Region = "eu-nl" | "eu-de" | "us-east" | "us-west"; + +// āœ… Allow readonly arrays for safe assignment from const literals +type Plan = { + id: PlanId; + name: string; + price: string; + specs: string; + typical: string; + features: readonly string[]; +}; + +type RegionOpt = { id: Region; label: string }; + +export default function DeployWizard({ + plans, + regions, + siteHostname, +}: { + plans: readonly Plan[]; + regions: readonly RegionOpt[]; + siteHostname: string; +}) { + const router = useRouter(); + const [step, setStep] = useState(1); + const [loading, setLoading] = useState(false); + + const [form, setForm] = useState<{ + plan: PlanId | ""; + edition: Edition | ""; + modLoader: ModLoader; + version: string; + region: Region | ""; + serverName: string; + subdomain: string; + email: string; + acceptEula: boolean; + notes: string; + }>({ + plan: "", + edition: "", + modLoader: "", + version: "latest", + region: "", + serverName: "", + subdomain: "", + email: "", + acceptEula: false, + notes: "", + }); + + const set = (key: K, value: (typeof form)[K]) => + setForm((f) => ({ ...f, [key]: value })); + + // Preselect plan from hash/query if present + if (typeof window !== "undefined" && !form.plan) { + const hash = window.location.hash; + const url = new URL(window.location.href); + const qp = url.searchParams.get("plan") as PlanId | null; + const fromHash = /plan=(starter|pro|network)/.exec(hash || "")?.[1] as PlanId | undefined; + const initial = qp || fromHash; + if (initial) set("plan", initial); + } + + const canContinue1 = !!form.plan; + const canContinue2 = + !!form.edition && + !!form.region && + !!form.version && + (form.edition !== "modded" || !!form.modLoader); + const canSubmit = + canContinue2 && + !!form.serverName && + !!form.email && + !!form.subdomain && + form.acceptEula; + + const handleSubmit = async () => { + if (!canSubmit) return; + setLoading(true); + + try { + const res = await fetch("/api/minecraft/create-server", { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-secret-token": process.env.NEXT_PUBLIC_FORM_SECRET || "", + }, + body: JSON.stringify(form), + }); + + if (!res.ok) throw new Error("Provisioning failed"); + + toast.success("Server provisioning started! Check your email for details."); + router.push("/minecraft/success"); + } catch (err) { + console.error(err); + toast.error("Something went wrong. Please try again."); + } finally { + setLoading(false); + } + }; + + return ( +
+ + {step === 1 && ( + +

+ 1) Choose a Plan +

+

+ You can change plans later. Network is custom—contact us for sizing. +

+ +
+ {plans.map((p) => ( + + ))} +
+ +
+ +
+
+ )} + + {step === 2 && ( + +

+ 2) Configure +

+
+ {/* Edition */} +
+ + +
+ + {/* Mod loader */} +
+ + +

+ Velocity is recommended for multi-server networks. +

+
+ + {/* Version */} +
+ + set("version", e.target.value)} + placeholder="latest or e.g. 1.20.6" + className="w-full rounded-lg border border-neutral-300 dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80 px-3 py-2" + /> +
+ + {/* Region */} +
+ + +
+
+ +
+ + +
+
+ )} + + {step === 3 && ( + +

+ 3) Details & Provision +

+
+
+
+ + set("serverName", e.target.value)} + placeholder="My Community Server" + className="w-full rounded-lg border border-neutral-300 dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80 px-3 py-2" + /> +
+
+ + set("email", e.target.value)} + placeholder="you@example.com" + className="w-full rounded-lg border border-neutral-300 dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80 px-3 py-2" + /> +
+
+ +
+
+ +
+ + set( + "subdomain", + e.target.value.replace(/[^a-z0-9-]/gi, "").toLowerCase() + ) + } + placeholder="myserver" + className="w-full rounded-lg border border-neutral-300 dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80 px-3 py-2" + /> + + .{siteHostname} + +
+

+ We’ll map this to your server on provision. +

+
+ +
+ + set("notes", e.target.value)} + placeholder="Plugins to preinstall, SFTP user, etc." + className="w-full rounded-lg border border-neutral-300 dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80 px-3 py-2" + /> +
+
+ + +
+ +
+ + +
+ +

+ We’ll send panel access and SFTP credentials to your email. All plans include + backups and monitoring. Modpacks & networks depend on resources and may + require custom sizing. +

+
+ )} +
+
+ ); +} diff --git a/web/app/minecraft/page.tsx b/web/app/minecraft/page.tsx new file mode 100644 index 0000000..0a043a0 --- /dev/null +++ b/web/app/minecraft/page.tsx @@ -0,0 +1,328 @@ +import type { Metadata } from "next"; +import Link from "next/link"; +import JsonLd from "@/components/JsonLd"; +import { site } from "@/lib/site"; +import DeployWizard from "./DeployWizard"; + +export const metadata: Metadata = { + title: "Managed Minecraft Server Hosting & Plugins | Van Hunen IT", + description: + "Lag-free, stable Minecraft hosting on a hardened VPS—backups, tuning, and monitoring included. Deploy a server in minutes or request custom plugin development.", +}; + +// Shared data (passed to the client wizard & used for SEO JSON-LD) +const plans = [ + { + id: "starter", + name: "Starter", + price: "€19/mo", + specs: "2 vCPU • 4 GB RAM • 40 GB SSD", + typical: "Up to ~20 players (optimized)", + features: [ + "Paper/Spigot or Bedrock", + "Daily backups + restore test", + "Basic tuning & monitoring", + ], + }, + { + id: "pro", + name: "Pro", + price: "€39/mo", + specs: "3 vCPU • 8 GB RAM • 80 GB SSD", + typical: "Up to ~60 players (optimized)", + features: [ + "Paper/Velocity or Bedrock + Geyser", + "Backups (2x/day) + restore test", + "Advanced tuning & monitoring", + ], + }, + { + id: "network", + name: "Network", + price: "Custom", + specs: "Dedicated VPS spec", + typical: "Networks & modpacks", + features: [ + "Velocity/Bungee multi-server", + "Backups (hourly) + restore test", + "Custom tuning & SLA", + ], + }, +] as const; + +const regions = [ + { id: "eu-nl", label: "EU — Netherlands" }, + { id: "eu-de", label: "EU — Germany" }, + { id: "us-east", label: "US — East" }, + { id: "us-west", label: "US — West" }, +] as const; + +const faqItems = [ + { + q: "Do you support both Java and Bedrock?", + a: "Yes. Java with Paper/Spigot or Velocity, and Bedrock with Geyser support. Modpacks (Forge/Fabric) are supported on resource-appropriate plans.", + }, + { + q: "How do backups work?", + a: "Automated backups are included with scheduled restore tests. We keep notes and timing so you know recovery is proven.", + }, + { + q: "Can I migrate from another host?", + a: "Yes. We can migrate files, plugins, and worlds. We’ll review your current setup and tune performance on the new server.", + }, + { + q: "Do you offer DDoS protection?", + a: "We apply baseline hardening and provider-level network protections. For advanced scenarios, we’ll discuss options during setup.", + }, + { + q: "What about uptime and incidents?", + a: "We monitor resources and uptime, document incidents with notes, and offer SLAs depending on your plan.", + }, +]; + +const serviceLd = { + "@context": "https://schema.org", + "@type": "Service", + serviceType: "Managed Minecraft Server Hosting & Plugin Development", + provider: { + "@type": "Organization", + name: site.name, + url: site.url, + logo: site.org.logo, + }, + areaServed: ["EU", "US"], + hasOfferCatalog: { + "@type": "OfferCatalog", + name: "Minecraft Hosting Plans", + itemListElement: plans.map((p) => ({ + "@type": "Offer", + name: p.name, + price: p.price, + description: `${p.specs} — ${p.typical}`, + url: `${site.url}/minecraft#deploy`, + category: "Minecraft Hosting", + })), + }, +}; + +const faqLd = { + "@context": "https://schema.org", + "@type": "FAQPage", + mainEntity: faqItems.map((i) => ({ + "@type": "Question", + name: i.q, + acceptedAnswer: { "@type": "Answer", text: i.a }, + })), +}; + +export default function MinecraftPage() { + const hostname = new URL(site.url).hostname; + + return ( +
+ {/* HERO */} +
+
+
+

+ + Managed Minecraft Server Hosting — Lag-Free & Done-for-You + +

+

+ Hardened VPS, tuned performance, backups with restore tests, and monitoring. Deploy your server in minutes or let us set it up for you. Need features? We build custom Paper/Spigot plugins with tests and docs. +

+ +
+ + Deploy a Server + + + Talk to an Engineer + +
+ + {/* Proof badges */} +
+
+

Stable TPS

+

tuned Paper/Velocity stacks

+
+
+

Restore-Proven

+

backups with timed drills

+
+
+

SLA-backed

+

monitoring & incident notes

+
+
+
+
+ + {/* BENEFITS */} +
+
+

+ Everything you need for smooth gameplay +

+
+ {[ + { t: "Performance Tuning", d: "Paper, Timings, async I/O, and caching where it counts." }, + { t: "Backups + Restore Tests", d: "Automated backups and scheduled restore drills with notes." }, + { t: "Monitoring & Incidents", d: "Uptime, resource alerts, clear incident notes & follow-up." }, + { t: "Security Basics", d: "Hardened OS, firewall rules, and safe update process." }, + ].map((b) => ( +
+

{b.t}

+

{b.d}

+
+ ))} +
+
+
+ + {/* PLANS */} +
+
+

Hosting Plans

+

+ Choose a plan that fits your community. Player counts are typical, not hard limits—tuning and plugins affect performance. +

+ +
+ {plans.map((p) => ( +
+
+

{p.name}

+
{p.price}
+
+
{p.specs}
+
{p.typical}
+ +
    + {p.features.map((f) => ( +
  • + āœ… + {f} +
  • + ))} +
+ + + {p.id === "network" ? "Request Custom Plan" : `Deploy ${p.name}`} + +
+ ))} +
+
+
+ + {/* PLUGIN DEVELOPMENT */} +
+
+
+
+

Minecraft Plugin Development

+

+ Custom Paper/Spigot plugins built to spec—tests, config, permissions, and docs included. + Ownership transferred to you after payment. +

+
    + {[ + "Feature scoping and milestones", + "Automated test suite & changelog", + "Config, permissions, and admin docs", + "Private repo transfer and handover", + ].map((li) => ( +
  • + šŸ”§ + {li} +
  • + ))} +
+ +
+ + Request Plugin Quote + + + Talk About Your Server + +
+
+ +
+
Example plugin ideas
+
    +
  • • Economy & shops with anti-dupe checks
  • +
  • • Claims / protection with region flags
  • +
  • • Cross-server chat via Velocity
  • +
  • • Mini-games scaffolding & leaderboards
  • +
+

+ (We’ll confirm feasibility and scope before building.) +

+
+
+
+
+ + {/* SELF-SERVICE DEPLOYMENT */} +
+
+

+ Deploy a Minecraft Server (Self-Service) +

+

+ Pick a plan, choose edition & version, set a region, and we’ll provision your server and email access details. +

+ + +
+
+ + {/* FAQ */} +
+
+

FAQ

+
+ {faqItems.map((i) => ( +
+

{i.q}

+

{i.a}

+
+ ))} +
+
+
+ + + +
+ ); +} diff --git a/web/app/page.tsx b/web/app/page.tsx index b8089fd..040654b 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -8,9 +8,9 @@ import JsonLd from "@/components/JsonLd"; import Link from "next/link"; export const metadata: Metadata = { - title: "SMB Website Reliability & Deliverability", + title: "Managed Hosting & Development — VPS, Websites & Minecraft | Van Hunen IT", description: - "DMARC-aligned email, Cloudflare edge security & speed, tested backups, and uptime watch for SMB sites. Fixed-scope sprints and care plans with real SLAs and before/after proof.", + "Managed VPS hosting (managed or owned), Managed Website hosting & care, Website development, and Managed Minecraft hosting & plugins. Self-service provisioning, SLAs, restore-tested backups, expert support.", }; export default function HomePage() { @@ -26,16 +26,20 @@ export default function HomePage() { const faqItems = [ { q: "How fast can you start?", - a: "Most sprints start within 2–3 business days after scope confirmation.", + a: "Most projects start within 2–3 business days after scope confirmation.", + }, + { + q: "Can I own the VPS through your platform?", + a: "Yes. Choose Owned mode on the VPS page. We provision into your cloud account via a secure connect flow. You keep full ownership; we still manage it.", + }, + { + q: "Do you support self-service deploys?", + a: "Yes. You can self-provision a VPS or deploy a Minecraft server in minutes—both include backups and monitoring by default.", }, { q: "Do you work under NDA?", a: "Yes—mutual NDA available on request; we keep credentials least-privilege.", }, - { - q: "Can we switch providers later?", - a: "Yes. Everything is documented; you own the accounts and artifacts. Month-to-month plans with a 30-day cancel policy.", - }, { q: "What’s your guarantee?", a: "We show proof of outcomes. If the agreed scope isn’t met, we make it right or refund the sprint fee.", @@ -56,6 +60,60 @@ export default function HomePage() { })), }; + const heroBullets = [ + { + title: "Managed or Owned VPS hosting", + body: "Hardened servers, monitoring, and verified backups—hosted by us or owned in your account.", + href: "/vps", + }, + { + title: "Managed Website hosting & care", + body: "Updates, uptime, security checks, and monthly restore-tested backups.", + href: "/services#website-care", + }, + { + title: "Website development", + body: "Fast Next.js sites, SEO-ready with deployment included.", + href: "/services#development", + }, + { + title: "Minecraft hosting & plugins", + body: "Self-service deploys, tuned performance, backups, and custom features.", + href: "/minecraft", + }, + ]; + + const services = [ + { + title: "Managed VPS Hosting (Managed or Owned)", + body: + "Secure, fast VPS hosting—server management, monitoring, and restore-tested backups. Provision on our platform or own it in your cloud.", + href: "/vps", + cta: "Provision a VPS →", + }, + { + title: "Managed Website Hosting & Care", + body: + "Fully managed website hosting & maintenance—updates, uptime, security checks, and monthly restore tests.", + href: "/services#website-care", + cta: "Start Managed Website Hosting →", + }, + { + title: "Website Development (Next.js)", + body: + "Launch a fast, SEO-ready site with modern tech, analytics, and deployment to your managed hosting.", + href: "/services#development", + cta: "Build My Website →", + }, + { + title: "Managed Minecraft Server Hosting & Plugins", + body: + "Lag-free, stable Minecraft hosting on a hardened VPS, plus custom Paper/Spigot plugins when you need them.", + href: "/minecraft", + cta: "Deploy a Server →", + }, + ]; + return (
{/* --- HERO --- */} @@ -64,27 +122,56 @@ export default function HomePage() {

- Fixes in days. Uptime for months. + Managed Hosting & Development — Fast, Secure, Done-for-You

- SMB website reliability and deliverability—implemented with the{" "} - Reliability Stackā„¢: DMARC-aligned email, Cloudflare edge - security & speed, tested backups, and uptime watch. Flat pricing. Before/after proof. + Get reliable Managed or Owned VPS hosting,{" "} + Managed Website hosting & care,{" "} + Website development, and{" "} + Minecraft server hosting & plugins. Self-service provisioning with{" "} + restore-tested backups and real SLAs—so you can focus on creating and growing.

-
+ {/* Hero bullets */} +
+ {heroBullets.map((b) => ( + +
{b.title}
+
{b.body}
+ + ))} +
+ + {/* Primary CTAs */} +
- Start a Free Reliability Check + Provision a VPS - Book a 15-min Fit Call + Manage My Website + + + Build My Website + + + Deploy Minecraft
@@ -92,11 +179,11 @@ export default function HomePage() {

+38% faster TTFB

-

after Cloudflare tuning

+

after edge & cache tuning

DMARC p=reject

-

in 48 hours, spoofing blocked

+

spoofing blocked in 48 hours

7m 12s restore

@@ -106,45 +193,20 @@ export default function HomePage() {
- {/* --- RELIABILITY STACK --- */} + {/* --- SERVICES --- */}

- The Reliability Stackā„¢ + Hosting & Development Services

- Four layers that make websites dependable. Implemented in a 1–3 day sprint, proven with before/after data. + Clear outcomes, flat pricing, and real SLAs—plus before/after proof on every engagement.

- {[ - { - title: "Email Deliverability", - body: - "Inbox-ready email with SPF/DKIM/DMARC alignment, monitoring, and reports. Stop spoofing and missing leads.", - href: "/services#email-deliverability", - }, - { - title: "Cloudflare Edge", - body: - "WAF & bot mitigation, HTTP/3, cache tuning, and origin shields for fewer attacks and faster TTFB.", - href: "/services#cloudflare", - }, - { - title: "Backups & Restore", - body: - "Automated backups with scheduled restore tests and a recovery runbook. Know you can recover, fast.", - href: "/services#backups", - }, - { - title: "Uptime & Incidents", - body: - "Monitors and SSL watch with clear incident notes and post-mortems. Reduce surprises and MTTR.", - href: "/services#uptime", - }, - ].map((card) => ( + {services.map((card) => (
- Explore → + {card.cta}
))} @@ -175,15 +237,15 @@ export default function HomePage() {
- {/* --- HOW IT WORKS (3 STEPS) --- */} + {/* --- HOW IT WORKS --- */}

- From audit to outcomes in 72 hours + From plan to live in days

- Diagnose the risks, implement the fixes, and prove the results—then choose the right Care plan. + Self-service provisioning or white-glove setup. We scope, set up, and verify—then hand you clear reporting and an SLA-backed care plan.

@@ -191,21 +253,18 @@ export default function HomePage() { {[ { step: "1", - title: "Diagnose", - body: - "DNS/email/edge scan, backup checks, and uptime review. Clear scope and fixed price before we start.", + title: "Plan", + body: "Technical review and goals—or use the wizard to self-provision.", }, { step: "2", - title: "Implement", - body: - "DMARC + Cloudflare + backups + monitors. Least-privilege access, change log, and rollback plan.", + title: "Set up", + body: "Provision VPS/hosting, deploy site or server, configure monitoring and backups.", }, { step: "3", - title: "Prove", - body: - "Before/after report, restore test timer, incident notes, and next-step plan you can share internally.", + title: "Verify", + body: "Before/after metrics, restore test timer, and next-step plan you can share internally.", }, ].map((s) => (
- Book a Fix Sprint (€490) + Get My Recommendation
@@ -233,11 +292,10 @@ export default function HomePage() { {/* --- PRICING --- */}
-

- Every plan includes DNS/email monitoring, automated backups with restore verification, uptime & SSL + Every plan includes monitoring, automated backups with restore verification, uptime & SSL watch, and a quarterly health summary.

@@ -262,23 +320,23 @@ export default function HomePage() {

- Ready to make your website reliable and inbox-ready? + Power, Performance & Peace of Mind — Managed for You.

- Start with a Fix Sprint or choose a Care plan that fits your business. We’ll prove the results. + Provision a VPS, manage your site, or deploy a Minecraft server—backed by real SLAs and restore-tested backups.

- Start Free Check + Provision a VPS - See Pricing & SLA + Deploy Minecraft
diff --git a/web/app/pricing/PricingConfigurator.tsx b/web/app/pricing/PricingConfigurator.tsx new file mode 100644 index 0000000..b080f23 --- /dev/null +++ b/web/app/pricing/PricingConfigurator.tsx @@ -0,0 +1,358 @@ +"use client"; + +import { useMemo, useState } from "react"; +import Link from "next/link"; + +// ---------- Types ---------- +export type CarePlan = { + id: string; + name: string; + bestFor: string; + monthlyPrice: number; + yearlyDiscount: number; // 0.1 = 10% + outcomes: readonly string[]; + inclusions: readonly string[]; + sla: string; + cta: { label: string; href: string }; + popular?: boolean; + contactOnly?: boolean; +}; + +export type VPSPlan = { + id: "solo" | "team" | "dedicated"; + name: string; + price: number | null; // null = custom + specs: string; + bestFor: string; +}; + +export type MCPlan = { + id: "starter" | "pro" | "network"; + name: string; + price: number | null; + specs: string; + typical: string; + features: readonly string[]; +}; + +// ---------- Main Component ---------- +export default function PricingConfigurator({ + carePlans, + vpsPlans, + minecraftPlans, +}: { + carePlans: readonly CarePlan[]; + vpsPlans: readonly VPSPlan[]; + minecraftPlans: readonly MCPlan[]; +}) { + const [tab, setTab] = useState<"care" | "vps" | "mc">("care"); + const [billing, setBilling] = useState<"monthly" | "yearly">("monthly"); + const [vpsOwnership, setVpsOwnership] = useState<"managed" | "owned">("managed"); + + return ( +
+ {/* Tabs */} +
+
+ {[ + { id: "care", label: "Managed Hosting & Care" }, + { id: "vps", label: "VPS (Managed or Owned)" }, + { id: "mc", label: "Minecraft Hosting" }, + ].map((t) => ( + + ))} +
+ + {/* Billing toggle */} + {tab === "care" && ( +
+ Billing: +
+ {(["monthly", "yearly"] as const).map((b) => ( + + ))} +
+
+ )} +
+ + {/* Panels */} +
+ {tab === "care" && } + {tab === "vps" && ( + + )} + {tab === "mc" && } +
+
+ ); +} + +// ---------- CARE ---------- +function CareGrid({ + plans, + billing, +}: { + plans: readonly CarePlan[]; + billing: "monthly" | "yearly"; +}) { + return ( +
+ {plans.map((p) => { + const price = + billing === "yearly" + ? Math.round(p.monthlyPrice * (1 - p.yearlyDiscount)) + : p.monthlyPrice; + + return ( +
+ {p.popular && ( +
+ Most Popular +
+ )} + +
+

{p.name}

+
+
+ €{price} + /mo +
+ {billing === "yearly" && ( +
billed annually (-10%)
+ )} +
+
+ +
+ {p.bestFor} +
+ +
    + {p.outcomes.map((o) => ( +
  • + šŸŽÆ + {o} +
  • + ))} + {p.inclusions.map((i) => ( +
  • + āœ… + {i} +
  • + ))} +
  • + šŸ›”ļø + {p.sla} +
  • +
+ +
+ + {p.cta.label} + +
+
+ ); + })} +
+ ); +} + +// ---------- VPS ---------- +function VPSGrid({ + plans, + ownership, + onOwnershipChange, +}: { + plans: readonly VPSPlan[]; + ownership: "managed" | "owned"; + onOwnershipChange: (m: "managed" | "owned") => void; +}) { + return ( +
+
+
+ Choose how you want to run your VPS. +
+
+ {(["managed", "owned"] as const).map((m) => ( + + ))} +
+
+ +
+ {plans.map((p) => ( +
+
+

{p.name}

+
+
+ {p.price ? ( + <> + €{p.price} + /mo + + ) : ( + "Custom" + )} +
+
+
+
{p.specs}
+
{p.bestFor}
+ +
    +
  • + šŸ›”ļø + CIS-style hardening, updates & monitoring +
  • +
  • + šŸ’¾ + Backups with scheduled restore tests +
  • +
  • + šŸ“ˆ + Incident notes & SLA-backed response +
  • +
+ +
+ {p.id === "dedicated" ? ( + + Request Custom Plan + + ) : ( + + {ownership === "managed" ? "Provision (Managed)" : "Provision (Owned)"} + + )} +
+ +

+ {ownership === "managed" + ? "We host & bill the VPS on our platform. Management included." + : "Provisioned into your cloud account via secure connect. You retain ownership."} +

+
+ ))} +
+
+ ); +} + +// ---------- MINECRAFT ---------- +function MinecraftGrid({ plans }: { plans: readonly MCPlan[] }) { + return ( +
+ {plans.map((p) => ( +
+
+

{p.name}

+
+ {p.price ? ( + <> + €{p.price} + /mo + + ) : ( + "Custom" + )} +
+
+
{p.specs}
+
{p.typical}
+ +
    + {p.features.map((f) => ( +
  • + āœ… + {f} +
  • + ))} +
+ +
+ {p.id === "network" ? ( + + Request Custom Plan + + ) : ( + + Deploy Server + + )} +
+ +

+ Backups with restore tests, tuning & monitoring included. Networks & modpacks may require custom sizing. +

+
+ ))} +
+ ); +} diff --git a/web/app/pricing/page.tsx b/web/app/pricing/page.tsx index ac74bc0..4e18075 100644 --- a/web/app/pricing/page.tsx +++ b/web/app/pricing/page.tsx @@ -1,45 +1,44 @@ // app/pricing/page.tsx import type { Metadata } from "next"; -import PricingTable from "@/components/pricing/PricingTable"; -import ComparisonTable from "@/components/pricing/ComparisonTable"; -import PlanRecommender from "@/components/pricing/PlanRecommender"; -import ROICalculator from "@/components/pricing/ROICalculator"; -import FAQ from "@/components/pricing/FAQ"; -import Guarantee from "@/components/pricing/Guarantee"; -import { Plan } from "@/components/pricing/types"; +import Link from "next/link"; +import { site } from "@/lib/site"; +import JsonLd from "@/components/JsonLd"; +import PricingConfigurator from "./PricingConfigurator"; export const metadata: Metadata = { - title: "Pricing & SLAs — Van Hunen IT", + title: "Plans, SLAs & Self-Service — Managed VPS, Websites & Minecraft | Van Hunen IT", description: - "Simple plans with real SLAs. Essential, Growth, Mission-Critical. Month-to-month, 30-day cancel, incident credits.", + "Choose Managed Hosting & Care, provision a VPS (managed or owned), or deploy a Minecraft server. SLAs, restore-tested backups, monitoring. Month-to-month.", }; -const plans: Plan[] = [ +// ---- Server-safe plan data (also used for JSON-LD) ---- // +const carePlans = [ { id: "essential", - name: "Essential Care", - bestFor: "Solo & micro businesses", + name: "Essential Managed Hosting", + bestFor: "Websites & VPS that need reliable care", monthlyPrice: 149, yearlyDiscount: 0.1, - outcomes: ["Inbox-ready email", "99.9% uptime"], + outcomes: ["Reliable care & monitoring", "99.9% uptime target"], inclusions: [ - "SPF/DKIM/DMARC monitoring", + "DNS & email monitoring (SPF/DKIM/DMARC)", "Automated backups + quarterly restore test", + "Managed updates (WordPress/Next.js)", "Uptime & SSL watch", "Incident credits", "Business-hours support (8Ɨ5)", ], sla: "Next-business-day first response (8Ɨ5)", - ctaLabel: "Start Essential", + cta: { label: "Start Essential", href: "/contact?type=website-care" }, popular: false, }, { id: "growth", - name: "Growth Care", - bestFor: "SMB team sites", + name: "Growth Managed Hosting", + bestFor: "Teams & growing sites", monthlyPrice: 299, yearlyDiscount: 0.1, - outcomes: ["99.95% uptime", "Faster TTFB"], + outcomes: ["99.95% uptime target", "Faster performance"], inclusions: [ "Everything in Essential", "Cloudflare WAF & bot tuning", @@ -47,72 +46,213 @@ const plans: Plan[] = [ "Priority incident handling", ], sla: "4-hour first response (8Ɨ5)", - ctaLabel: "Start Growth", + cta: { label: "Start Growth", href: "/contact?type=website-care" }, popular: true, }, { id: "mission", - name: "Mission-Critical", - bestFor: "High-traffic & 24/7", + name: "Mission-Critical Managed Hosting", + bestFor: "High-traffic & 24/7 operations", monthlyPrice: 649, yearlyDiscount: 0.1, - outcomes: ["99.99% uptime", "24/7 on-call"], - inclusions: [ - "Everything in Growth", - "24/7 paging", - "Weekly checks", - "DR runbook & drills", - ], + outcomes: ["99.99% uptime target", "24/7 on-call"], + inclusions: ["Everything in Growth", "24/7 paging", "Weekly checks", "DR runbook & drills"], sla: "1-hour first response (24/7)", - ctaLabel: "Talk to us", + cta: { label: "Talk to Us", href: "/contact?type=website-care" }, popular: false, contactOnly: true, }, -]; +] as const; + +const vpsPlans = [ + { + id: "solo", + name: "Solo VPS", + price: 24, // €/mo + specs: "2 vCPU • 4 GB RAM • 50 GB NVMe", + bestFor: "Small apps, staging, low-traffic services", + }, + { + id: "team", + name: "Team VPS", + price: 49, + specs: "4 vCPU • 8 GB RAM • 100 GB NVMe", + bestFor: "Production apps, WordPress/Next.js, APIs", + }, + { + id: "dedicated", + name: "Dedicated / Custom", + price: null, // custom + specs: "Dedicated VPS/metal — tailored", + bestFor: "High traffic, networks, or compliance", + }, +] as const; + +const minecraftPlans = [ + { + id: "starter", + name: "Starter", + price: 19, + specs: "2 vCPU • 4 GB RAM • 40 GB SSD", + typical: "Up to ~20 players (optimized)", + features: ["Paper/Spigot or Bedrock", "Daily backups + restore test", "Basic tuning & monitoring"], + }, + { + id: "pro", + name: "Pro", + price: 39, + specs: "3 vCPU • 8 GB RAM • 80 GB SSD", + typical: "Up to ~60 players (optimized)", + features: [ + "Paper/Velocity or Bedrock + Geyser", + "Backups (2x/day) + restore test", + "Advanced tuning & monitoring", + ], + }, + { + id: "network", + name: "Network", + price: null, + specs: "Dedicated VPS spec", + typical: "Networks & modpacks", + features: ["Velocity/Bungee multi-server", "Backups (hourly) + restore test", "Custom tuning & SLA"], + }, +] as const; + +// ---- JSON-LD (Offers for three catalogs) ---- // +const pricingLd = { + "@context": "https://schema.org", + "@type": "OfferCatalog", + name: "Van Hunen IT — Plans & Catalog", + url: `${site.url}/pricing`, + itemListElement: [ + { + "@type": "OfferCatalog", + name: "Managed Hosting & Care", + itemListElement: carePlans.map((p) => ({ + "@type": "Offer", + name: p.name, + price: `€${p.monthlyPrice}/mo`, + priceCurrency: "EUR", + url: `${site.url}/pricing`, + description: `${p.bestFor} — SLA: ${p.sla}`, + })), + }, + { + "@type": "OfferCatalog", + name: "VPS (Managed or Owned)", + itemListElement: vpsPlans.map((p) => ({ + "@type": "Offer", + name: p.name, + price: p.price ? `€${p.price}/mo` : "Custom", + priceCurrency: "EUR", + url: `${site.url}/vps#deploy`, + description: `${p.specs} — ${p.bestFor}`, + })), + }, + { + "@type": "OfferCatalog", + name: "Minecraft Hosting", + itemListElement: minecraftPlans.map((p) => ({ + "@type": "Offer", + name: p.name, + price: p.price ? `€${p.price}/mo` : "Custom", + priceCurrency: "EUR", + url: `${site.url}/minecraft#deploy`, + description: `${p.specs} — ${p.typical}`, + })), + }, + ], +}; export default function PricingPage() { return ( -
-
-

- Simple plans with real SLAs +
+ {/* HERO */} +
+

+ Plans, SLAs & Self-Service

-

- Pick the care level that matches your traffic and risk. Month-to-month, 30-day - cancel. Fix Sprint available for urgent issues. +

+ Pick **Managed Hosting & Care**, provision a **VPS (managed or owned)**, or **deploy a Minecraft server**. + Month-to-month, 30-day cancel, restore-tested backups, real SLAs.

+
+ + Provision a VPS + + + Deploy Minecraft + +
- {/* Engaging element #1: Billing toggle inside table */} -
- -

- Prices exclude VAT. Annual billing saves 10%. + {/* NEW PRICING EXPERIENCE */} +

+ + +

+ Prices exclude VAT. Annual billing saves 10% on Managed Hosting & Care. VPS and Minecraft prices shown are base infrastructure fees; management is included on our platform. Owned VPS incurs provider charges in your account.

- {/* Engaging element #2: Plan recommender */} -
- + {/* TRUST / GUARANTEE */} +
+
+ {[ + { t: "Restore-Tested Backups", s: "We time drills and keep notes." }, + { t: "SLA-Backed Response", s: "Credits per plan. 24/7 available." }, + { t: "Month-to-Month", s: "30-day cancel. No lock-in." }, + ].map((i) => ( +
+
{i.t}
+
{i.s}
+
+ ))} +
- {/* Comparison matrix */} -
- + {/* FAQ */} +
+

FAQ

+
+ {[ + { + q: "What’s the difference between Managed and Owned VPS?", + a: "Managed = we host & bill the VPS on our platform (backups, monitoring, SLAs included). Owned = we provision into your cloud account via a secure connect; you retain ownership. Both include management.", + }, + { + q: "Can I migrate my current site or server?", + a: "Yes. We handle data transfer, DNS cutover, and rollback. We also tune performance and verify backups with a restore drill.", + }, + { + q: "Do you support modpacks and networks for Minecraft?", + a: "Yes—Forge/Fabric and Velocity/Bungee networks are supported, sized to resources. Use the Network/Custom option or contact us.", + }, + { + q: "How do incident credits work?", + a: "If we miss your SLA, we credit according to your plan’s policy. Details are included in your agreement.", + }, + { + q: "Do you offer NDAs and least-privilege access?", + a: "Yes—mutual NDA available; we only request the credentials needed for the task.", + }, + ].map((i) => ( +
+

{i.q}

+

{i.a}

+
+ ))} +
+ +
+ + Get My Recommendation + +
- {/* Engaging element #3: ROI calculator */} -
- -
- -
- -
- -
- -
+
); } diff --git a/web/app/services/page.tsx b/web/app/services/page.tsx index e4b0915..e39c8ab 100644 --- a/web/app/services/page.tsx +++ b/web/app/services/page.tsx @@ -1,159 +1,445 @@ // app/services/page.tsx -import { Metadata } from "next"; -import { getAllServices, SERVICE_CATEGORIES, type ServiceCategoryId } from "@/lib/services"; -import ServiceCard from "@/components/ServiceCard"; +import type { Metadata } from "next"; import Link from "next/link"; +import JsonLd from "@/components/JsonLd"; +import { site } from "@/lib/site"; export const revalidate = 86400; export const metadata: Metadata = { - title: "Services — Website Reliability for SMBs | Van Hunen IT", + title: "Services — Managed Hosting, Websites & Minecraft | Van Hunen IT", description: - "Fixed-scope sprints and care plans for SMB website reliability: email deliverability (DMARC), Cloudflare edge security & speed, tested backups, and uptime watch.", + "Managed or Owned VPS hosting, Managed Website hosting & care, Website development, and Minecraft hosting & plugins. Clear outcomes, flat pricing, SLAs, and before/after proof.", alternates: { canonical: "/services" }, }; -export default function ServicesPage() { - const services = getAllServices(); +type Card = { + title: string; + body: string; + href: string; + cta: string; +}; - // Emphasize core Reliability first; keep the rest discoverable. - const categories: ServiceCategoryId[] = [ - "web-performance", - "infrastructure-devops", - "dev-platforms", - "migrations", - "web-dev", - "minecraft", - ]; +type Category = { + id: + | "web-dev" + | "web-performance" + | "minecraft" + | "infrastructure-devops" + | "migrations" + | "dev-platforms"; + anchor: string; + label: string; + lead: string; + cards: Card[]; +}; + +const CATEGORIES: Category[] = [ + { + id: "web-dev", + anchor: "web-dev", + label: "Website Development", + lead: + "Fast, SEO-ready websites with modern tooling and clean deployments. We build for reliability first.", + cards: [ + { + title: "Next.js Website Build", + body: + "Design system, content structure, analytics, basic SEO, and production deployment. Optimized for Core Web Vitals.", + href: "/contact?type=development", + cta: "Build My Website →", + }, + { + title: "Landing Pages & Microsites", + body: + "High-converting pages with performance and tracking baked in. Perfect for campaigns and product launches.", + href: "/contact?type=development", + cta: "Start a Landing Page →", + }, + { + title: "Headless CMS Setup", + body: + "Content modeling, editor workflows, preview, and safe publishing. Optional migration from legacy CMS.", + href: "/contact?type=development", + cta: "Discuss CMS →", + }, + ], + }, + { + id: "web-performance", + anchor: "web-performance", + label: "Web Reliability & Performance (incl. Website Hosting)", + lead: + "We make sites dependable: faster TTFB, verified backups, uptime & SSL watch, and incident notes you can share.", + cards: [ + { + title: "Managed Website Hosting & Care", + body: + "Updates, uptime, security checks, and monthly restore-tested backups. Real SLAs and incident credits.", + href: "/pricing#care", + cta: "Start Website Care →", + }, + { + title: "Cloudflare Edge Hardening", + body: + "WAF & bot rules, cache & HTTP/3 tuning, origin shields, and fewer attacks for faster pages.", + href: "/contact?type=website-care", + cta: "Harden My Edge →", + }, + { + title: "Email Deliverability (SPF/DKIM/DMARC)", + body: + "Block spoofing, align auth, and fix lead-loss from junk folders. Monitoring and reports included.", + href: "/contact?type=website-care", + cta: "Fix My Email →", + }, + { + title: "Backups + Restore Drills", + body: + "Automated backups plus timed restore tests with notes. Know recovery is proven—not just configured.", + href: "/contact?type=website-care", + cta: "Verify My Backups →", + }, + { + title: "Performance & Web Vitals", + body: + "TTFB improvements, image/CDN strategy, and Core Web Vitals uplift with before/after proof.", + href: "/contact?type=website-care", + cta: "Boost My Speed →", + }, + ], + }, + { + id: "minecraft", + anchor: "minecraft", + label: "Minecraft Services", + lead: + "Lag-free servers on a hardened VPS with backups, monitoring, and tuning. Need features? We build custom plugins.", + cards: [ + { + title: "Managed Minecraft Hosting", + body: + "Java (Paper/Spigot/Velocity) and Bedrock (Geyser) supported. Backups with restore tests and incident notes.", + href: "/minecraft#deploy", + cta: "Deploy a Server →", + }, + { + title: "Minecraft Plugin Development", + body: + "Custom plugins with tests, config, permissions, and docs. Private repo and handover on completion.", + href: "/contact?type=plugin", + cta: "Request Plugin Quote →", + }, + { + title: "Migrations & Tuning", + body: + "Move worlds and plugins safely, clean up timings, and stabilize TPS. Optional network (Velocity/Bungee).", + href: "/contact?type=minecraft-hosting", + cta: "Plan My Migration →", + }, + ], + }, + { + id: "infrastructure-devops", + anchor: "infrastructure-devops", + label: "Infrastructure & DevOps", + lead: + "Managed or Owned VPS, monitoring, and incident response—plus safe automation for deploys and updates.", + cards: [ + { + title: "Managed VPS Hosting", + body: + "CIS-style hardening, updates, monitoring, and restore-tested backups. SLA-backed response.", + href: "/vps#deploy", + cta: "Provision (Managed) →", + }, + { + title: "Owned VPS (Your Account)", + body: + "We provision into your cloud via secure connect. You retain ownership; we still manage and monitor.", + href: "/vps#deploy", + cta: "Provision (Owned) →", + }, + { + title: "Monitoring & Incident Notes", + body: + "Uptime, resource alerts, clear incident write-ups, and post-mortems that drive improvements.", + href: "/contact?type=vps", + cta: "Set Up Monitoring →", + }, + ], + }, + { + id: "migrations", + anchor: "migrations", + label: "Migrations & Refreshes", + lead: + "Safer cutovers with rollback plans. Move hosting, upgrade stacks, and modernize without downtime surprises.", + cards: [ + { + title: "Hosting & DNS Migration", + body: + "Plan, test, and cut over with a rollback path. Documented steps and after-action report.", + href: "/contact?type=website-care", + cta: "Migrate Hosting →", + }, + { + title: "WordPress → Next.js", + body: + "Modern rebuilds with headless options and faster delivery. SEO preservation and redirects included.", + href: "/contact?type=development", + cta: "Discuss Rebuild →", + }, + { + title: "Platform Upgrades", + body: + "PHP/Node/OpenSSL updates, TLS/HTTP versions, and dependency hygiene without breaking the app.", + href: "/contact?type=vps", + cta: "Plan My Upgrade →", + }, + ], + }, + { + id: "dev-platforms", + anchor: "dev-platforms", + label: "Developer Platforms & Tooling", + lead: + "Make shipping easier: pipelines, environments, and guardrails that keep production stable.", + cards: [ + { + title: "CI/CD & Environments", + body: + "Staging, previews, and blue/green deployment workflows. Safer changes, faster feedback.", + href: "/contact?type=development", + cta: "Improve Deploys →", + }, + { + title: "Observability Basics", + body: + "Structured logs, metrics, and health checks that find issues before users do.", + href: "/contact?type=vps", + cta: "Add Observability →", + }, + { + title: "Runbooks & Readiness", + body: + "Clear runbooks and checklists for on-call, upgrades, and incident handling.", + href: "/contact?type=website-care", + cta: "Create Runbooks →", + }, + ], + }, +] as const; + +// JSON-LD OfferCatalog: top-level sections surfaced for SEO +const servicesLd = { + "@context": "https://schema.org", + "@type": "OfferCatalog", + name: "Van Hunen IT — Service Catalog", + url: `${site.url}/services`, + itemListElement: CATEGORIES.map((cat) => ({ + "@type": "OfferCatalog", + name: cat.label, + url: `${site.url}/services#${cat.anchor}`, + itemListElement: cat.cards.map((c) => ({ + "@type": "Offer", + name: c.title, + description: c.body, + url: `${site.url}${c.href.startsWith("/") ? c.href : `/${c.href}`}`, + priceCurrency: "EUR", + })), + })), +}; + +export default function ServicesPage() { + const chips = CATEGORIES.map((c) => ({ id: c.id, label: c.label, anchor: c.anchor })); return (
- {/* --- Hero Header --- */} + {/* HERO */}
+

- Services that make websites reliable + Services: Managed Hosting, Websites & Minecraft

-

- Fixed-scope sprints and care plans for{" "} - email deliverability, Cloudflare edge security & speed,{" "} - backups with restore tests, and uptime watch. Clear outcomes, flat pricing, - and before/after proof you can keep. +

+ Managed or Owned VPS, Managed Website hosting & care, Website development, and Minecraft hosting & plugins. + Clear outcomes, flat pricing, real SLAs—and before/after proof.

+ {/* Category chips */}
- {categories.map((id) => ( + {chips.map((c) => ( - {SERVICE_CATEGORIES[id].label} + {c.label} ))}
-
+ {/* Quick actions */} +
- See pricing + Provision a VPS - Book a 15-min Fit Call + Deploy Minecraft
- {/* --- Service Categories --- */} -
- {categories.map((id, index) => { - const list = services.filter((s) => s.category === id); - if (!list.length) return null; - - const headingId = `${id}-heading`; - const sectionClasses = `relative py-16 scroll-mt-24 ${ - index % 2 === 0 - ? "bg-white dark:bg-neutral-900/50" - : "bg-neutral-50 dark:bg-neutral-900/30" - } rounded-2xl mb-12 shadow-sm`; - - return ( -
+
+ {[ + { + id: "vps", + title: "Managed VPS (Managed or Owned)", + body: "Hardened & monitored VPS with restore-tested backups.", + href: "/vps#deploy", + cta: "Provision VPS →", + }, + { + id: "website-care", + title: "Managed Website Hosting & Care", + body: "Updates, uptime, security checks & monthly restore tests.", + href: "/pricing#care", + cta: "Start Website Care →", + }, + { + id: "development", + title: "Website Development (Next.js)", + body: "Fast, SEO-ready sites with analytics & deployment.", + href: "/contact?type=development", + cta: "Build My Website →", + }, + { + id: "minecraft", + title: "Minecraft Hosting & Plugins", + body: "Lag-free servers on a hardened VPS + custom plugins.", + href: "/minecraft#deploy", + cta: "Deploy a Server →", + }, + ].map((card) => ( +
-
-
-
-

- {SERVICE_CATEGORIES[id].label} -

- - Jump to top ↑ - -
+
+

+ {card.title} +

+

{card.body}

+ + {card.cta} + +
+ ))} +
+
-
- {list.map((svc, i) => ( -
- -
- ))} -
+ {/* SECTIONS */} +
+ {CATEGORIES.map((cat, index) => ( +
+
+ +
+
+

+ {cat.label} +

+ + Jump to top ↑ +
-
- ); - })} + +

+ {cat.lead} +

+ +
+ {cat.cards.map((card, i) => ( +
+

{card.title}

+

{card.body}

+ + {card.cta} + +
+ ))} +
+
+

+ ))}
- {/* --- CTA footer --- */} + {/* CTA FOOTER */}

- Ready to improve reliability and deliverability? + Power, Performance & Peace of Mind — Managed for You.

- Tell us about your site. We’ll recommend the right Fix Sprint or Care plan and show you the expected - before/after. + Provision a VPS, manage your site, or deploy a Minecraft server—backed by real SLAs and restore-tested backups.

- Compare plans + Compare Plans - Contact us + Get My Recommendation
+ +
); } diff --git a/web/app/vps/VPSDeployWizard.tsx b/web/app/vps/VPSDeployWizard.tsx new file mode 100644 index 0000000..509c9e7 --- /dev/null +++ b/web/app/vps/VPSDeployWizard.tsx @@ -0,0 +1,410 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import { AnimatePresence, motion } from "framer-motion"; +import { toast } from "sonner"; + +type PlanId = "solo" | "team" | "dedicated"; +type Region = "eu-nl" | "eu-de" | "us-east" | "us-west"; +type OSImage = "ubuntu-24-04" | "ubuntu-22-04" | "debian-12"; +type OwnershipMode = "managed" | "owned"; + +type Plan = { + id: PlanId; + name: string; + price: string; + specs: string; + bestFor: string; + features: readonly string[]; +}; + +type RegionOpt = { id: Region; label: string }; +type OSOpt = { id: OSImage; label: string }; + +export default function VPSDeployWizard({ + plans, + regions, + osImages, + siteHostname, +}: { + plans: readonly Plan[]; + regions: readonly RegionOpt[]; + osImages: readonly OSOpt[]; + siteHostname: string; +}) { + const router = useRouter(); + const [step, setStep] = useState(1); + const [loading, setLoading] = useState(false); + + const [form, setForm] = useState<{ + plan: PlanId | ""; + region: Region | ""; + osImage: OSImage | ""; + hostname: string; + fqdn: string; + sshPublicKey: string; + ownership: OwnershipMode; + provider: "" | "hetzner" | "digitalocean" | "vultr"; + email: string; + notes: string; + acceptTerms: boolean; + enableBackups: boolean; + }>({ + plan: "", + region: "", + osImage: "ubuntu-24-04", + hostname: "", + fqdn: "", + sshPublicKey: "", + ownership: "managed", + provider: "", + email: "", + notes: "", + acceptTerms: false, + enableBackups: true, + }); + + const set = (key: K, value: (typeof form)[K]) => + setForm((f) => ({ ...f, [key]: value })); + + // Preselect plan from hash/query if present + if (typeof window !== "undefined" && !form.plan) { + const hash = window.location.hash; + const url = new URL(window.location.href); + const qp = url.searchParams.get("plan") as PlanId | null; + const fromHash = /plan=(solo|team|dedicated)/.exec(hash || "")?.[1] as PlanId | undefined; + const initial = qp || fromHash; + if (initial) set("plan", initial); + } + + const canContinue1 = !!form.plan; + const canContinue2 = !!form.region && !!form.osImage; + const canSubmit = + canContinue2 && + !!form.hostname && + !!form.email && + form.acceptTerms && + (form.ownership === "managed" || (form.ownership === "owned" && !!form.provider)); + + const handleSubmit = async () => { + if (!canSubmit) return; + setLoading(true); + + try { + const res = await fetch("/api/vps/create", { + method: "POST", + headers: { + "Content-Type": "application/json", + "x-secret-token": process.env.NEXT_PUBLIC_FORM_SECRET || "", + }, + body: JSON.stringify(form), + }); + + if (!res.ok) throw new Error("Provisioning failed"); + + toast.success( + form.ownership === "owned" + ? "Owned VPS request received! Check your email to securely connect your provider." + : "VPS provisioning started! Check your email for access details." + ); + router.push("/vps/success"); + } catch (err) { + console.error(err); + toast.error("Something went wrong. Please try again."); + } finally { + setLoading(false); + } + }; + + return ( +
+ + {step === 1 && ( + +

1) Choose a Plan

+

+ You can change plans later. Dedicated is custom—contact us for sizing. +

+ +
+ {plans.map((p) => ( + + ))} +
+ +
+ +
+
+ )} + + {step === 2 && ( + +

2) Configure

+
+ {/* Region */} +
+ + +
+ + {/* OS */} +
+ + +
+ + {/* Hostname */} +
+ + set("hostname", e.target.value.replace(/[^a-z0-9-.]/gi, "").toLowerCase())} + placeholder="app-1" + className="w-full rounded-lg border border-neutral-300 dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80 px-3 py-2" + /> +
+ + {/* FQDN */} +
+ +
+ set("fqdn", e.target.value.toLowerCase())} + placeholder={`app.${siteHostname}`} + className="w-full rounded-lg border border-neutral-300 dark:border-neutral-700 bg-white/80 dark:bg-neutral-900/80 px-3 py-2" + /> +
+

+ We can map a subdomain like app.{siteHostname}. +

+
+ + {/* SSH Public Key */} +
+ +