2026-02-17 09:05:22 +00:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import Image from "next/image";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import { useState } from "react";
|
2026-04-13 15:20:26 +00:00
|
|
|
import { X } from "lucide-react";
|
|
|
|
|
import LandingSiteNav from "@/components/landing-page/landing-site-nav";
|
2026-02-23 07:47:35 +00:00
|
|
|
import { Input } from "../ui/input";
|
|
|
|
|
import { Label } from "../ui/label";
|
|
|
|
|
import { Textarea } from "../ui/textarea";
|
|
|
|
|
import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
|
2026-04-10 07:21:29 +00:00
|
|
|
import type { CmsHeroContent } from "@/types/cms-landing";
|
2026-02-17 09:05:22 +00:00
|
|
|
|
2026-04-10 07:21:29 +00:00
|
|
|
function isExternalUrl(url: string) {
|
|
|
|
|
return /^https?:\/\//i.test(url);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default function Header({ hero }: { hero?: CmsHeroContent | null }) {
|
2026-02-23 07:47:35 +00:00
|
|
|
const [contactOpen, setContactOpen] = useState(false);
|
2026-02-17 09:05:22 +00:00
|
|
|
|
2026-04-10 18:54:11 +00:00
|
|
|
// Only main title is required in CMS; optional fields stay empty (no placeholder dashes or fake CTAs).
|
|
|
|
|
const fallbackHeadline = "Beyond Expectations to Build Reputation.";
|
|
|
|
|
const title = hero?.primary_title?.trim()
|
|
|
|
|
? hero.primary_title.trim()
|
|
|
|
|
: !hero
|
|
|
|
|
? fallbackHeadline
|
|
|
|
|
: "";
|
2026-04-10 07:21:29 +00:00
|
|
|
const subtitle = hero?.secondary_title?.trim();
|
|
|
|
|
const lead = hero?.description?.trim();
|
2026-04-10 18:54:11 +00:00
|
|
|
const primaryCta = hero?.primary_cta?.trim();
|
2026-04-10 07:21:29 +00:00
|
|
|
const secondaryCta = hero?.secondary_cta_text?.trim();
|
|
|
|
|
const heroImg = hero?.images?.[0]?.image_url?.trim();
|
|
|
|
|
|
2026-02-17 09:05:22 +00:00
|
|
|
return (
|
2026-02-23 07:47:35 +00:00
|
|
|
<>
|
2026-04-13 15:20:26 +00:00
|
|
|
<LandingSiteNav />
|
2026-02-17 09:05:22 +00:00
|
|
|
|
2026-04-13 15:20:26 +00:00
|
|
|
<header className="relative w-full bg-white pt-20 md:pt-[5.5rem]">
|
2026-02-23 07:47:35 +00:00
|
|
|
{/* HERO */}
|
|
|
|
|
<div className="container mx-auto flex min-h-[90vh] items-center px-6">
|
|
|
|
|
<div className="flex-1 space-y-6">
|
2026-04-10 07:21:29 +00:00
|
|
|
<h1 className="text-4xl font-extrabold leading-tight whitespace-pre-line md:text-6xl">
|
|
|
|
|
{title}
|
2026-02-23 07:47:35 +00:00
|
|
|
</h1>
|
2026-04-10 07:21:29 +00:00
|
|
|
{subtitle ? (
|
|
|
|
|
<p className="text-lg text-gray-600 md:text-xl">{subtitle}</p>
|
|
|
|
|
) : null}
|
|
|
|
|
{lead ? (
|
|
|
|
|
<p className="max-w-xl text-sm leading-relaxed text-gray-600 md:text-base whitespace-pre-line">
|
|
|
|
|
{lead}
|
|
|
|
|
</p>
|
|
|
|
|
) : null}
|
2026-02-17 09:05:22 +00:00
|
|
|
|
2026-04-10 18:54:11 +00:00
|
|
|
{(primaryCta || secondaryCta) ? (
|
|
|
|
|
<div className="flex flex-wrap gap-3">
|
|
|
|
|
{primaryCta ? (
|
|
|
|
|
<Button
|
|
|
|
|
size="lg"
|
|
|
|
|
onClick={() => setContactOpen(true)}
|
|
|
|
|
className="rounded-full bg-[#966314] px-8 py-6 text-base hover:bg-[#7c520f]"
|
|
|
|
|
>
|
|
|
|
|
{primaryCta}
|
|
|
|
|
</Button>
|
|
|
|
|
) : null}
|
|
|
|
|
{secondaryCta ? (
|
|
|
|
|
<Button
|
|
|
|
|
size="lg"
|
|
|
|
|
variant="outline"
|
|
|
|
|
className="rounded-full border-[#966314] px-8 py-6 text-base text-[#966314]"
|
|
|
|
|
type="button"
|
|
|
|
|
>
|
|
|
|
|
{secondaryCta}
|
|
|
|
|
</Button>
|
|
|
|
|
) : null}
|
|
|
|
|
</div>
|
|
|
|
|
) : null}
|
2026-02-23 07:47:35 +00:00
|
|
|
</div>
|
|
|
|
|
|
2026-04-10 07:21:29 +00:00
|
|
|
<div className="relative hidden max-h-[min(90vh,520px)] flex-1 justify-end md:flex">
|
|
|
|
|
{heroImg && isExternalUrl(heroImg) ? (
|
|
|
|
|
// eslint-disable-next-line @next/next/no-img-element
|
|
|
|
|
<img
|
|
|
|
|
src={heroImg}
|
|
|
|
|
alt=""
|
|
|
|
|
width={520}
|
|
|
|
|
height={520}
|
|
|
|
|
className="max-h-[520px] w-auto object-contain"
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<Image
|
|
|
|
|
src={heroImg || "/image/img1.png"}
|
|
|
|
|
alt="Illustration"
|
|
|
|
|
width={520}
|
|
|
|
|
height={520}
|
|
|
|
|
className="object-contain"
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2026-02-23 07:47:35 +00:00
|
|
|
</div>
|
2026-02-17 09:05:22 +00:00
|
|
|
</div>
|
2026-02-23 07:47:35 +00:00
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
{/* CONTACT MODAL */}
|
|
|
|
|
{contactOpen && <ContactDialog onClose={() => setContactOpen(false)} />}
|
|
|
|
|
</>
|
2026-02-17 09:05:22 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-23 07:47:35 +00:00
|
|
|
function ContactDialog({ onClose }: { onClose: () => void }) {
|
|
|
|
|
const [contactMethod, setContactMethod] = useState("office");
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="fixed inset-0 z-[999] bg-black/40 backdrop-blur-sm flex items-end md:items-center justify-center">
|
|
|
|
|
{/* CONTAINER */}
|
|
|
|
|
<div
|
|
|
|
|
className="
|
|
|
|
|
w-full
|
|
|
|
|
h-[90vh] md:h-auto
|
|
|
|
|
md:max-w-2xl
|
|
|
|
|
bg-white
|
|
|
|
|
rounded-t-3xl md:rounded-2xl
|
|
|
|
|
p-5 md:p-8
|
|
|
|
|
shadow-2xl
|
|
|
|
|
relative
|
|
|
|
|
overflow-y-auto
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
{/* Close Button */}
|
|
|
|
|
<button
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
className="absolute right-4 top-4 md:right-6 md:top-6 text-gray-500 hover:text-black"
|
|
|
|
|
>
|
|
|
|
|
<X size={20} />
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
{/* Header */}
|
|
|
|
|
<h2 className="text-xl md:text-2xl font-bold text-[#966314] mb-2">
|
|
|
|
|
Contact Us
|
|
|
|
|
</h2>
|
|
|
|
|
<p className="text-sm md:text-base text-gray-500 mb-6">
|
|
|
|
|
Select a contact method and fill in your personal information. We will
|
|
|
|
|
get back to you shortly.
|
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
{/* Contact Method */}
|
|
|
|
|
<div className="space-y-3 md:space-y-4 mb-6">
|
|
|
|
|
<RadioGroup
|
|
|
|
|
value={contactMethod}
|
|
|
|
|
onValueChange={setContactMethod}
|
|
|
|
|
className="space-y-3"
|
|
|
|
|
>
|
|
|
|
|
{/* Option 1 */}
|
|
|
|
|
<div
|
|
|
|
|
className={`flex items-start space-x-3 rounded-xl p-4 cursor-pointer border transition ${
|
|
|
|
|
contactMethod === "office" ? "border-[#966314]" : "border-muted"
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<RadioGroupItem value="office" id="office" className="mt-1" />
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<Label htmlFor="office" className="font-medium cursor-pointer">
|
|
|
|
|
Office Presentation
|
|
|
|
|
</Label>
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
Our team will come to your office for a presentation.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Option 2 */}
|
|
|
|
|
<div
|
|
|
|
|
className={`flex items-start space-x-3 rounded-xl p-4 cursor-pointer border transition ${
|
|
|
|
|
contactMethod === "hais" ? "border-[#966314]" : "border-muted"
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<RadioGroupItem value="hais" id="hais" className="mt-1" />
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<Label htmlFor="hais" className="font-medium cursor-pointer">
|
|
|
|
|
Via HAIs
|
|
|
|
|
</Label>
|
|
|
|
|
<p className="text-sm text-muted-foreground">
|
|
|
|
|
Online consultation through HAIs platform.
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</RadioGroup>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Form */}
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="fullName">
|
|
|
|
|
Full Name <span className="text-red-500">*</span>
|
|
|
|
|
</Label>
|
|
|
|
|
<Input id="fullName" placeholder="Enter full name" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="email">
|
|
|
|
|
Email <span className="text-red-500">*</span>
|
|
|
|
|
</Label>
|
|
|
|
|
<Input id="email" type="email" placeholder="email@example.com" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="phone">
|
|
|
|
|
Phone Number <span className="text-red-500">*</span>
|
|
|
|
|
</Label>
|
|
|
|
|
<Input id="phone" placeholder="08xx xxxx xxxx" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="company">
|
|
|
|
|
Company Name <span className="text-red-500">*</span>
|
|
|
|
|
</Label>
|
|
|
|
|
<Input id="company" placeholder="PT. Example Company" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2 mt-4">
|
|
|
|
|
<Label htmlFor="message">Message / Requirement</Label>
|
|
|
|
|
<Textarea
|
|
|
|
|
id="message"
|
|
|
|
|
placeholder="Describe your needs or questions..."
|
|
|
|
|
className="min-h-[120px]"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Buttons */}
|
|
|
|
|
<div className="mt-6 flex flex-col-reverse md:flex-row gap-3 md:justify-end">
|
|
|
|
|
<button
|
|
|
|
|
onClick={onClose}
|
|
|
|
|
className="w-full md:w-auto rounded-xl border px-6 py-3 hover:bg-gray-100"
|
|
|
|
|
>
|
|
|
|
|
Cancel
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
<button className="w-full md:w-auto rounded-xl bg-[#966314] px-6 py-3 text-white hover:bg-[#7c520f]">
|
|
|
|
|
Send Request
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|