UNPKG

@exabytellc/utils

Version:

EB react utils to make everything a little easier!

108 lines (98 loc) 3.91 kB
import { useCallback, useMemo } from "react"; /** * A custom hook for building and managing URLs with dynamic parameters. * * This hook helps you construct a URL by combining a base URL with additional path segments * and URL parameters. You can specify parameters to be merged with the current URL parameters. * It also supports encoding of parameters and the ability to build URLs with placeholder paths. * * @param {string} base - The base URL to which parts and parameters will be added. * @param {...UrlPart} parts - A list of `UrlPart` objects that define dynamic URL segments. * * @returns {Object} The `build` function for constructing the URL and `params` which holds * the current parameters. * * @example * const { build, params } = useUrlBuilder('/user', userIdPart, statusPart); * const url = build({ userId: 123, status: 'active' }); // "/user/123/active" * console.log(params); // { userId: 123, status: 'active' } */ export default function useUrlBuilder(urlParams, base, ...parts) { const build = useCallback( (params = {}, keepCurrent = false) => { let url = base; // Merge the passed params with the current params from the URL const mergedParams = keepCurrent ? params : { ...urlParams, ...params }; // Iterate over the parts to replace placeholders with actual values from mergedParams parts.forEach((part) => { let built = part.build(mergedParams); if (built) url += built; }); return url; }, [base, parts, urlParams] ); // include urlParams in the dependencies const params = useMemo(() => { let obj = { ...urlParams }; parts.forEach((part) => { obj[part.param] = part.get(obj); }); return obj; }, [parts, urlParams]); return { build, params }; } /** * Represents a dynamic segment of a URL, allowing you to specify path placeholders, * encode/decode values, and manage URL parameters. * * This function helps build dynamic URL parts by replacing placeholders with actual * parameter values, and it supports different encoding types such as base64 and base-36. * * @param {string} param - The name of the parameter to be used in the path. * @param {string} path - The URL path containing placeholders (e.g., "/users/:userId"). * @param {string} [encoding='none'] - The encoding type for parameter values. Can be 'none', 'base64', or 'num-hex'. * * @returns {Object} An object containing `param`, `build`, and `get` functions. * * @example * const userIdPart = UrlPart('userId', '/user/:userId', 'base64'); * const url = userIdPart.build({ userId: '123' }); // "/user/MTIz" * const value = userIdPart.get({ userId: 'MTIz' }); // "123" */ export function UrlPart(param, path, encoding = 'none') { const build = (params = {}) => { var value = params[param]; if (value) { try { switch (encoding) { case 'base64': value = window.btoa(value); // Base64 encoding break; case 'num-hex': value = Number(value).toString(36); // Convert number to base-36 (shorter and more readable than hex) break; } value = encodeURIComponent(value); return path.replace(`:${param}`, value); } catch (_) { return; } } }; const get = (params = {}) => { var value = params[param]; if (value) { try { value = decodeURIComponent(value); switch (encoding) { case 'base64': value = window.atob(value); // Base64 decoding break; case 'num-hex': value = parseInt(value, 36); // Decode base-36 back to number break; } return value; } catch (_) { return; } } }; return { param, build, get }; }