Skip to main content

Provider Components

The template/components/providers/ directory contains all application-level React context providers. These providers wrap the component tree to supply global state for theming, data fetching, error handling, confirmations, navigation tracking, settings, and layout configuration.

Architecture Overview

Source Files

FileDescription
index.tsBarrel exports for all providers
query-provider.tsxTanStack React Query client provider
theme-provider.tsxDark/light/system theme provider
error-provider.tsxGlobal error boundary wrapper
filter-provider.tsxFilter context delegation provider
layout-provider.tsxLayout theme and editor context
confirm-provider.tsxPromise-based confirmation dialog
navigation-provider.tsxNavigation and initial load tracking
settings-provider.tsxSite-wide feature flags and settings
settings-modal-provider.tsxSettings modal open/close state

QueryClientProvider

Wraps the application with TanStack React Query's QueryClientProvider, enabling data fetching hooks throughout the tree. Includes React Query Devtools in development.

Props

PropTypeDefaultDescription
childrenReactNoderequiredChild components
dehydratedStateunknownundefinedServer-side dehydrated query state

Usage

import { QueryClientProvider } from '@/components/providers';

function RootLayout({ children, dehydratedState }) {
return (
<QueryClientProvider dehydratedState={dehydratedState}>
{children}
</QueryClientProvider>
);
}

Behavior

  • Uses getQueryClient() from @/lib/query-client to obtain a singleton client
  • Stores the client in a useRef to prevent re-creation across renders
  • Renders <ReactQueryDevtools> only when NODE_ENV === 'development'
  • Re-exports dehydrate from @tanstack/react-query for server-side usage

ThemeProvider

Wraps the application with next-themes for dark mode, light mode, and system preference detection.

Usage

import { ThemeProvider } from '@/components/providers';

<ThemeProvider>
{children}
</ThemeProvider>

Configuration

SettingValueDescription
enableSystemtrueRespect OS-level dark/light preference
attribute"class"Apply theme via CSS class on <html>
defaultTheme"system"Default to system preference

ErrorProvider

Wraps children in a global ErrorBoundary component that catches and displays React rendering errors gracefully.

Usage

import { ErrorProvider } from '@/components/providers';

<ErrorProvider>
{children}
</ErrorProvider>

The ErrorBoundary is imported from @/components/error-boundary and provides a fallback UI when a component tree throws during rendering.

ConfirmProvider

Provides a Promise-based confirmation dialog system accessible anywhere in the component tree via the useConfirm() hook.

Type Definitions

interface ConfirmOptions {
title?: string;
message: string;
confirmText?: string;
cancelText?: string;
variant?: 'danger' | 'warning' | 'info';
}

interface ConfirmContextValue {
confirm: (options: ConfirmOptions) => Promise<boolean>;
}

Usage

import { ConfirmProvider, useConfirm } from '@/components/providers';

// Wrap in provider
<ConfirmProvider>{children}</ConfirmProvider>

// In a child component
function DeleteButton({ onDelete }) {
const { confirm } = useConfirm();

const handleDelete = async () => {
const confirmed = await confirm({
title: 'Delete Item',
message: 'Are you sure you want to delete this item?',
confirmText: 'Delete',
variant: 'danger',
});
if (confirmed) {
onDelete();
}
};

return <button onClick={handleDelete}>Delete</button>;
}

Variant Styles

VariantIcon BackgroundIcon ColorButton Color
dangerRedRedbg-red-600
warningOrangeOrangebg-orange-600
info (default)BlueBluebg-blue-600

Dialog Features

  • Modal overlay with z-9999 stacking context
  • Animated entrance (animate-in fade-in zoom-in-95)
  • Close button (X icon) in the top-right corner
  • Customizable confirm and cancel button text (defaults: "Confirm" / "Cancel")
  • Promise resolves true on confirm, false on cancel or dismiss

Tracks whether the current page load is the initial navigation or a subsequent client-side navigation. Useful for controlling animations, skeleton displays, and data-fetching behavior on first load versus route changes.

Type Definition

interface NavigationContextType {
isInitialLoad: boolean;
}

Usage

import { NavigationProvider, useNavigation } from '@/components/providers';

// Wrap in provider
<NavigationProvider>{children}</NavigationProvider>

// In a child component
function PageContent() {
const { isInitialLoad } = useNavigation();

if (isInitialLoad) {
return <FullPageSkeleton />;
}
return <TransitionAnimation>{content}</TransitionAnimation>;
}

Behavior

  • Starts with isInitialLoad = true
  • Watches usePathname() for changes
  • Sets isInitialLoad = false on the first pathname change
  • Uses a ref to track the previous pathname and avoid unnecessary state updates

SettingsProvider

Provides site-wide configuration and feature flags to the entire application. Supplies header settings, footer settings, location settings, and data-existence flags.

Type Definitions

interface SettingsContextValue {
// Feature enabled flags (from config)
categoriesEnabled: boolean;
tagsEnabled: boolean;
companiesEnabled: boolean;
surveysEnabled: boolean;
// Data existence flags (from database/content)
hasCategories: boolean;
hasTags: boolean;
hasCollections: boolean;
hasGlobalSurveys: boolean;
// Settings objects
headerSettings: HeaderSettings;
footerSettings: FooterSettings;
locationSettings: LocationSettings;
}

Props

PropTypeDefaultDescription
categoriesEnabledbooleanrequiredWhether categories feature is on
tagsEnabledbooleanrequiredWhether tags feature is on
companiesEnabledbooleanrequiredWhether companies feature is on
surveysEnabledbooleanrequiredWhether surveys feature is on
hasCategoriesbooleanrequiredWhether categories exist in data
hasTagsbooleanrequiredWhether tags exist in data
hasCollectionsbooleanrequiredWhether collections exist in data
hasGlobalSurveysbooleanrequiredWhether global surveys exist
headerSettingsHeaderSettingsrequiredHeader configuration
footerSettingsFooterSettingsrequiredFooter configuration
locationSettingsLocationConfigSettingsundefinedLocation filter configuration

Usage

import { SettingsProvider, useSettings } from '@/components/providers';

// In a child component
function FeatureSection() {
const { categoriesEnabled, hasTags, headerSettings } = useSettings();

if (!categoriesEnabled) return null;
// ...
}

Header Settings Defaults

const DEFAULT_HEADER_SETTINGS: HeaderSettings = {
submitEnabled: true,
pricingEnabled: true,
layoutEnabled: true,
languageEnabled: true,
themeEnabled: true,
moreEnabled: true,
settingsEnabled: true,
layoutDefault: 'home1',
paginationDefault: 'standard',
themeDefault: 'light',
};
const DEFAULT_FOOTER_SETTINGS: FooterSettings = {
subscribeEnabled: true,
versionEnabled: true,
themeSelectorEnabled: true,
};

Fallback Behavior

The useSettings() hook provides a fallback value when used outside the provider (backward compatibility), returning all features enabled with default header, footer, and location settings.

Location Settings Mapping

The provider receives LocationConfigSettings (snake_case from the config file) and maps it to the runtime LocationSettings (camelCase) using mapLocationConfigToRuntime().

SettingsModalProvider

Manages the open/close state of the site settings modal. Provides keyboard shortcut handling and focus management.

Type Definition

interface SettingsModalContextValue {
isOpen: boolean;
openModal: () => void;
closeModal: () => void;
toggleModal: () => void;
}

Usage

import { SettingsModalProvider, SettingsModalContext } from '@/components/providers';
import { useContext } from 'react';

// In a child component
function SettingsButton() {
const { openModal } = useContext(SettingsModalContext);
return <button onClick={openModal}>Settings</button>;
}

Features

  • Focus restoration: Stores the previously focused element and restores focus on close
  • Escape key handling: Closes the modal when Escape is pressed
  • Body scroll lock: Prevents background scrolling while the modal is open (document.body.style.overflow = 'hidden')

FilterProvider

A thin wrapper that delegates to FilterContextProvider from the filters module.

import { FilterProvider } from '@/components/providers';

<FilterProvider>{children}</FilterProvider>

See Filter UI Components for the full filter context documentation.

LayoutProvider

Composes the LayoutThemeProvider (for layout view switching) and EditorContextProvider (for inline editing) into a single provider.

Props

PropTypeDefaultDescription
childrenReactNoderequiredChild components
configDefaults{ defaultView?: string }undefinedDefault layout configuration

Usage

import { LayoutProvider } from '@/components/providers';

<LayoutProvider configDefaults={{ defaultView: 'grid' }}>
{children}
</LayoutProvider>

Dependencies

  • @tanstack/react-query -- Query client and devtools
  • next-themes -- Theme management
  • next/navigation -- usePathname for route tracking
  • @/components/error-boundary -- Error boundary component
  • @/components/filters/context/filter-context -- Filter context
  • @/components/context -- LayoutThemeProvider
  • @/lib/editor -- EditorContextProvider
  • @/lib/types/location -- Location settings types and mapping
  • @/lib/content -- Header, footer, and location config types