Fazekit

Code

"use client";
import * as React from "react";
import { MotionConfig, useReducedMotion } from "motion/react";
import { cn } from "@/lib/utils";
import { defaultPhotoData, type PhotoData } from "./data";
import { Availability } from "./sections/availability";
import { Faq } from "./sections/faq";
import { Footer } from "./sections/footer";
import { Hero } from "./sections/hero";
import { Inquiry, type InquiryPreset, type InquiryRequest } from "./sections/inquiry";
import { Navbar } from "./sections/navbar";
import { Packages, Process } from "./sections/packages";
import { About, Portfolio } from "./sections/portfolio";
import { Studio } from "./sections/studio";
import { Testimonials } from "./sections/testimonials";
import { LF_DISPLAY_STACK, scrollToId, ThemeStyle, useOpenStatus } from "./sections/ui";

export type { PhotoData, InquiryRequest };
export { defaultPhotoData };

export interface PhotographerTemplateProps {
  /** Override any top-level content group (business, portfolio, packages, availability…). Missing groups fall back to the demo content. */
  data?: Partial<PhotoData>;
  /** Called when someone sends the inquiry form. Return a promise to keep the loading state until your API answers. */
  onInquire?: (inquiry: InquiryRequest) => void | Promise<void>;
  className?: string;
}

const SCOPE = "lf-theme";

export function PhotographerTemplate({ data, onInquire, className }: PhotographerTemplateProps) {
  const d = React.useMemo(() => ({ ...defaultPhotoData, ...data }), [data]);
  const reduce = useReducedMotion();
  const status = useOpenStatus(d.studio.hours, d.business.timeZone);
  const [preset, setPreset] = React.useState<InquiryPreset | null>(null);
  const go = (id: string) => scrollToId(id, reduce);
  const inquireWith = (p: Omit<InquiryPreset, "nonce">) => {
    setPreset((prev) => ({ ...p, nonce: (prev?.nonce ?? 0) + 1 }));
    go("inquire");
  };

  return (
    <MotionConfig reducedMotion="user">
      <ThemeStyle scope={SCOPE} theme={d.theme} />
      <div className={cn(SCOPE, "relative w-full bg-background text-foreground antialiased selection:bg-primary/20", className)} style={{ "--lf-display": LF_DISPLAY_STACK } as React.CSSProperties}>
        <Navbar business={d.business} links={d.nav} status={status} onInquire={() => go("availability")} />
        <main>
          <Hero hero={d.hero} onInquire={() => go("availability")} onPortfolio={() => go("portfolio")} />
          <About about={d.about} />
          <Portfolio portfolio={d.portfolio} />
          <Packages packages={d.packages} business={d.business} onChoose={(c) => inquireWith({ packageId: c.packageId, addOns: c.addOns })} />
          <Process process={d.process} />
          <Availability availability={d.availability} business={d.business} onPickDate={(date) => inquireWith({ date })} />
          <Testimonials testimonials={d.testimonials} />
          <Inquiry inquiry={d.inquiry} packages={d.packages} availability={d.availability} business={d.business} preset={preset} onInquire={onInquire} />
          <Faq faq={d.faq} business={d.business} />
          <Studio visit={d.studio} business={d.business} status={status} />
        </main>
        <Footer footer={d.footer} business={d.business} />
      </div>
    </MotionConfig>
  );
}

More in Landing Pages

View all →