Fazekit

Code

"use client";
import * as React from "react";
import { MotionConfig, useReducedMotion } from "motion/react";
import { cn } from "@/lib/utils";
import { defaultGarageData, type GarageData } from "./data";
import { Faq } from "./sections/faq";
import { Footer } from "./sections/footer";
import { Hero, SeasonBanner } from "./sections/hero";
import { Navbar } from "./sections/navbar";
import { Quote, type QuotePreset, type QuoteRequest } from "./sections/quote";
import { Reviews } from "./sections/reviews";
import { Process, Services } from "./sections/services";
import { Tow } from "./sections/tow";
import { Trust } from "./sections/trust";
import { scrollToId, ThemeStyle, TQ_DISPLAY_STACK, useOpenStatus } from "./sections/ui";
import { Visit } from "./sections/visit";

export type { GarageData, QuoteRequest };
export { defaultGarageData };

export interface AutoRepairTemplateProps {
  /** Override any top-level content group (business, services, hours…). Missing groups fall back to the demo content. */
  data?: Partial<GarageData>;
  /** Called with the quote request (including the selected photo `File`s). Return a promise to keep the loading state. */
  onQuote?: (quote: QuoteRequest) => void | Promise<void>;
  className?: string;
}

const SCOPE = "tq-theme";

export function AutoRepairTemplate({ data, onQuote, className }: AutoRepairTemplateProps) {
  const d = React.useMemo(() => ({ ...defaultGarageData, ...data }), [data]);
  const reduce = useReducedMotion();
  const status = useOpenStatus(d.visit.hours, d.business.timeZone);
  const [preset, setPreset] = React.useState<QuotePreset | null>(null);
  const toQuote = React.useCallback(() => scrollToId("quote", reduce), [reduce]);
  const quoteFor = (serviceId: string) => {
    setPreset((p) => ({ serviceId, nonce: (p?.nonce ?? 0) + 1 }));
    toQuote();
  };

  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/25", className)} style={{ "--tq-display": TQ_DISPLAY_STACK } as React.CSSProperties}>
        <SeasonBanner seasons={d.seasons} timeZone={d.business.timeZone} onAction={quoteFor} />
        <Navbar business={d.business} links={d.nav} status={status} onQuote={toQuote} />
        <main>
          <Hero hero={d.hero} status={status} onQuote={toQuote} onServices={() => scrollToId("services", reduce)} />
          <Services services={d.services} business={d.business} onQuoteService={quoteFor} />
          <Process process={d.process} />
          <Trust trust={d.trust} />
          <Quote quote={d.quote} services={d.services.items} business={d.business} preset={preset} onQuote={onQuote} />
          <Tow tow={d.tow} business={d.business} />
          <Reviews reviews={d.reviews} />
          <Faq faq={d.faq} business={d.business} />
          <Visit visit={d.visit} business={d.business} status={status} />
        </main>
        <Footer footer={d.footer} business={d.business} />
      </div>
    </MotionConfig>
  );
}

More in Landing Pages

View all →