@exabytellc/utils
Version:
EB react utils to make everything a little easier!
108 lines (98 loc) • 3.91 kB
JavaScript
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 };
}