'use client' /** * Centralized URL query parameter management hooks using nuqs * * This file provides type-safe, performant query parameter management * that doesn't trigger full page refreshes (shallow routing). * * Best practices from nuqs documentation: * - Use useQueryState for single parameters * - Use useQueryStates for multiple related parameters (atomic updates) * - Always provide parsers with defaults for type safety * - Use shallow routing to avoid unnecessary re-renders */ import { createParser, useQueryState, useQueryStates } from 'nuqs' /** * Modal State Query Parameters * Manages modal visibility and configuration via URL */ export const PRICING_MODAL_QUERY_PARAM = 'pricing' export const PRICING_MODAL_QUERY_VALUE = 'open' const parseAsPricingModal = createParser({ parse: (value) => (value === PRICING_MODAL_QUERY_VALUE ? true : null), serialize: (value) => (value ? PRICING_MODAL_QUERY_VALUE : ''), }) .withDefault(false) .withOptions({ history: 'push' }) /** * Hook to manage pricing modal state via URL * @returns [isOpen, setIsOpen] - Tuple like useState * * @example * const [isOpen, setIsOpen] = usePricingModal() * setIsOpen(true) // Sets ?pricing=open * setIsOpen(false) // Removes ?pricing */ export function usePricingModal() { return useQueryState(PRICING_MODAL_QUERY_PARAM, parseAsPricingModal) } /** * Plugin Installation Query Parameters */ const PACKAGE_IDS_PARAM = 'package-ids' const BUNDLE_INFO_PARAM = 'bundle-info' type BundleInfoQuery = { org: string name: string version: string } const parseAsPackageId = createParser({ parse: (value) => { try { const parsed = JSON.parse(value) if (Array.isArray(parsed)) { const first = parsed[0] return typeof first === 'string' ? first : null } return value } catch { return value } }, serialize: (value) => JSON.stringify([value]), }) const parseAsBundleInfo = createParser({ parse: (value) => { try { const parsed = JSON.parse(value) as Partial if ( parsed && typeof parsed.org === 'string' && typeof parsed.name === 'string' && typeof parsed.version === 'string' ) { return { org: parsed.org, name: parsed.name, version: parsed.version } } } catch { return null } return null }, serialize: (value) => JSON.stringify(value), }) /** * Hook to manage plugin installation state via URL * @returns [installState, setInstallState] - installState includes parsed packageId and bundleInfo * * @example * const [installState, setInstallState] = usePluginInstallation() * setInstallState({ packageId: 'org/plugin' }) // Sets ?package-ids=["org/plugin"] * setInstallState({ bundleInfo: { org: 'org', name: 'bundle', version: '1.0.0' } }) // Sets ?bundle-info=... * setInstallState(null) // Clears installation params */ export function usePluginInstallation() { return useQueryStates( { packageId: parseAsPackageId, bundleInfo: parseAsBundleInfo, }, { urlKeys: { packageId: PACKAGE_IDS_PARAM, bundleInfo: BUNDLE_INFO_PARAM, }, }, ) }