Files
supabase/apps/studio/hooks/misc/useQueryStateWithSelect.ts
T
Francesco Sansalvadore cb045c9559 Chore: add param routing on panels (#40184)
* chore(studio): add useQueryStateWithSelect hook to handle nested param routing on panels
* handleErrorOnDelete fn for useQueryStateWithSelect
2025-11-12 15:58:31 +01:00

59 lines
1.8 KiB
TypeScript

import { MutableRefObject, useEffect, useMemo } from 'react'
import { parseAsString, useQueryState } from 'nuqs'
import { toast } from 'sonner'
/**
* Hook for managing URL query parameters with a custom select function and error handling.
*
* @param enabled - Whether error handling is active (shows error when selectedId exists but select returns undefined)
* @param urlKey - The query parameter key (e.g., 'edit', 'delete')
* @param select - Function to transform the selected ID into the desired value (returns undefined if not found)
* @param onError - Callback invoked when enabled is true and selectedId exists but select returns undefined
*
* @returns Object with:
* - value: The result of select(selectedId) or undefined
* - setValue: Function to set/clear the selected ID in the URL
*/
export function useQueryStateWithSelect<T>({
enabled,
urlKey,
select,
onError,
}: {
enabled: boolean
urlKey: string
select: (id: string) => T | undefined
onError: (error: Error, selectedId: string) => void
}) {
const [selectedId, setSelectedId] = useQueryState(
urlKey,
parseAsString.withOptions({ history: 'push', clearOnDefault: true })
)
const value = useMemo(() => (selectedId ? select(selectedId) : undefined), [selectedId, select])
useEffect(() => {
if (enabled && selectedId && !value) {
onError(new Error(`not found`), selectedId)
setSelectedId(null)
}
}, [enabled, onError, selectedId, setSelectedId, value])
return {
value,
setValue: setSelectedId as (value: string | null) => void,
}
}
export const handleErrorOnDelete = (
deletingIdRef: MutableRefObject<string | null>,
selectedId: string,
errorMessage: string
) => {
if (selectedId !== deletingIdRef.current) {
toast.error(errorMessage)
} else {
deletingIdRef.current = null
}
}