import { GoConfig, RouterBindings, ResourceContext, matchResourceFromRoute, ParseResponse, } from "@refinedev/core"; import { useParams, useLocation, useNavigate, Link } from "@remix-run/react"; import { parse, stringify } from "qs"; import React, { ComponentProps, useCallback, useContext } from "react"; import { paramsFromCurrentPath } from "./params-from-current-path"; import { convertToNumberIfPossible } from "./convert-to-number-if-possible"; export const stringifyConfig = { addQueryPrefix: true, skipNulls: true, arrayFormat: "indices" as const, encode: false, encodeValuesOnly: true, }; export const routerBindings: RouterBindings = { go: () => { const { search: existingSearch, hash: existingHash } = useLocation(); const navigate = useNavigate(); const fn = useCallback( ({ to, type, query, hash, options: { keepQuery, keepHash } = {}, }: GoConfig) => { /** Construct query params */ const urlQuery = { ...(keepQuery && existingSearch && parse(existingSearch, { ignoreQueryPrefix: true })), ...query, }; if (urlQuery.to) { urlQuery.to = encodeURIComponent(`${urlQuery.to}`); } const hasUrlQuery = Object.keys(urlQuery).length > 0; /** Get hash */ const urlHash = `#${( hash || (keepHash && existingHash) || "" ).replace(/^#/, "")}`; const hasUrlHash = urlHash.length > 1; const urlTo = to || ""; const fullPath = `${urlTo}${ hasUrlQuery ? stringify(urlQuery, stringifyConfig) : "" }${hasUrlHash ? urlHash : ""}`; if (type === "path") { return fullPath; } /** Navigate to the url */ return navigate(fullPath, { replace: type === "replace", }); }, [existingHash, existingSearch, navigate], ); return fn; }, back: () => { const navigate = useNavigate(); return () => { navigate(-1); }; }, parse: () => { const params = useParams(); const { pathname, search } = useLocation(); const { resources } = useContext(ResourceContext); const { resource, action, matchedRoute } = React.useMemo(() => { return matchResourceFromRoute(pathname, resources); }, [resources, pathname]); const inferredParams = matchedRoute && pathname ? paramsFromCurrentPath(pathname, matchedRoute) : {}; const inferredId = inferredParams.id; const fn = useCallback(() => { const parsedSearch = parse(search, { ignoreQueryPrefix: true }); const combinedParams = { ...inferredParams, ...params, ...parsedSearch, }; const response: ParseResponse = { ...(resource && { resource }), ...(action && { action }), ...(inferredId && { id: decodeURIComponent(inferredId) }), ...(params?.id && { id: decodeURIComponent(params.id) }), // ...(params?.action && { action: params.action }), // lets see if there is a need for this pathname, params: { ...combinedParams, current: convertToNumberIfPossible( combinedParams.current as string, ) as number | undefined, pageSize: convertToNumberIfPossible( combinedParams.pageSize as string, ) as number | undefined, to: combinedParams.to ? decodeURIComponent(combinedParams.to as string) : undefined, }, }; return response; }, [ pathname, search, params, resource, action, inferredParams, inferredId, ]); return fn; }, Link: React.forwardRef< HTMLAnchorElement, ComponentProps> >(function RefineLink(props, ref) { return ; }), };