Skip to content

Commit 54356c6

Browse files
authored
chore: Cleanup utils, add JSDoc comments (#661)
1 parent f7c40e9 commit 54356c6

25 files changed

Lines changed: 227 additions & 69 deletions

web/src/lib/utils/__tests__/formatPageTitle.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ describe("formatPageTitle", () => {
66
expect(formatPageTitle("Court Order")).toEqual("Court Order · Namesake");
77
});
88

9-
it("renders the title with custom divider", () => {
9+
it("renders the title with custom delimiter", () => {
1010
expect(formatPageTitle("Court Order", " - ")).toEqual(
1111
"Court Order - Namesake",
1212
);
@@ -18,7 +18,7 @@ describe("formatPageTitle", () => {
1818
);
1919
});
2020

21-
it("hides the divider when site title is not provided", () => {
21+
it("hides the delimiter when site title is not provided", () => {
2222
expect(formatPageTitle("Test Page", " · ", null)).toEqual("Test Page");
2323
});
2424

web/src/lib/utils/createOgImageResponse.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ type OgImageOptions = {
1010
origin: string;
1111
};
1212

13+
/**
14+
* Given a subhead, title, and color, return a rendered PNG Open Graph
15+
* image response for social sharing previews.
16+
*
17+
* @example
18+
* await createOgImageResponse({
19+
* subhead: "Massachusetts",
20+
* title: "Plan your name change",
21+
* origin: "https://namesake.fyi",
22+
* })
23+
* // ImageResponse (PNG, 1200x630)
24+
*/
1325
export async function createOgImageResponse({
1426
subhead,
1527
title,
Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,17 @@
11
/**
2-
* Derives current age from a date-of-birth string (YYYY-MM-DD).
2+
* Given a date-of-birth string (YYYY-MM-DD), return the current age.
33
* Treats the input as a calendar date with no timezone.
4+
*
5+
* @example
6+
* deriveCurrentAge("1990-06-15") // assuming today is 2026-06-24
7+
* // 36
48
*/
59
export const deriveCurrentAge = (dateOfBirth?: string): number | undefined => {
6-
if (typeof dateOfBirth !== "string" || !dateOfBirth) {
7-
return undefined;
8-
}
10+
if (typeof dateOfBirth !== "string" || !dateOfBirth) return undefined;
911

1012
const birth = new Date(dateOfBirth);
11-
if (Number.isNaN(birth.getTime())) {
12-
return undefined;
13-
}
13+
if (Number.isNaN(birth.getTime())) return undefined;
1414

15-
const today = new Date();
16-
let age = today.getFullYear() - birth.getFullYear();
17-
18-
const hasBirthdayOccurredThisYear =
19-
today.getMonth() > birth.getMonth() ||
20-
(today.getMonth() === birth.getMonth() &&
21-
today.getDate() >= birth.getDate());
22-
23-
if (!hasBirthdayOccurredThisYear) age -= 1;
24-
25-
return age;
15+
const elapsed = new Date(Date.now() - birth.getTime());
16+
return elapsed.getUTCFullYear() - new Date(0).getUTCFullYear();
2617
};

web/src/lib/utils/fetchLocationResults.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ export interface GeoapifyResult {
1212
place_id: string;
1313
}
1414

15+
/**
16+
* Given partial address text, return matching location results from the
17+
* Geoapify-backed location API.
18+
*
19+
* @example
20+
* await fetchLocations("123 Main St, Boston")
21+
* // [{ formatted: "123 Main St, Boston, MA 02108, United States", ... }]
22+
*/
1523
export async function fetchLocations(
1624
text: string,
1725
signal?: AbortSignal,
@@ -36,6 +44,14 @@ async function sleep(durationMs: number, signal?: AbortSignal) {
3644
});
3745
}
3846

47+
/**
48+
* Given a debounce delay, return an async list loader for `<ComboBox>`-style
49+
* location fields, debouncing requests and giving up on the API after one failure.
50+
*
51+
* @example
52+
* createLocationLoader(200)
53+
* // ({ signal, filterText }) => Promise<{ items: GeoapifyResult[] }>
54+
*/
3955
export function createLocationLoader(
4056
debounceMs = 200,
4157
): AsyncListLoadFunction<GeoapifyResult, string> {

web/src/lib/utils/fetchPovertyGuideline.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ export interface PovertyGuideline {
99
}
1010

1111
/**
12-
* Fetches the federal poverty guideline for a given year, state, and
13-
* household size from the HHS ASPE API. Household size is clamped to 1–8
14-
* per API constraints. Returns null on any failure.
12+
* Given a year, state, and household size, return the federal poverty
13+
* guideline from the HHS ASPE API, or null on failure. Household size is
14+
* clamped to 1–8 per API constraints.
15+
*
16+
* @example
17+
* await fetchPovertyGuideline(2025, 3, "ma")
18+
* // { year: 2025, state: "ma", householdSize: 3, povertyThreshold: ... }
1519
*/
1620
export async function fetchPovertyGuideline(
1721
year: number,

web/src/lib/utils/fetchYouTubeVideoDetails.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ export interface YouTubeOEmbedResponse {
44
thumbnail_url: string;
55
}
66

7+
/**
8+
* Given a YouTube video URL, return its title, author, and thumbnail via
9+
* the oEmbed API, or null if the request fails.
10+
*
11+
* @example
12+
* await fetchYouTubeVideoDetails("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
13+
* // { title: "...", author_name: "...", thumbnail_url: "..." }
14+
*/
715
export async function fetchYouTubeVideoDetails(
816
url: string,
917
): Promise<YouTubeOEmbedResponse | null> {

web/src/lib/utils/formatAddress.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ type Address = {
55
zip?: string;
66
};
77

8+
/**
9+
* Given the parts of a mailing address, return the present ones joined together.
10+
*
11+
* @example
12+
* formatAddress({ street: "123 Main St", city: "Boston", state: "MA", zip: "02108" })
13+
* // "123 Main St, Boston, MA, 02108"
14+
*/
815
export const formatAddress = ({ street, city, state, zip }: Address) => {
916
return [street, city, state, zip].filter(Boolean).join(", ");
1017
};

web/src/lib/utils/formatBirthplaceCountryOrState.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import { COUNTRIES } from "#constants/countries";
22
import { JURISDICTIONS } from "#constants/jurisdictions";
33

4+
/**
5+
* Given a birthplace country and/or state, return the country name
6+
* if born outside the US, or the state name otherwise.
7+
*
8+
* @example
9+
* formatBirthplaceCountryOrState("MX")
10+
* // "Mexico"
11+
* formatBirthplaceCountryOrState("US", "MA")
12+
* // "Massachusetts"
13+
*/
414
export const formatBirthplaceCountryOrState = (
515
birthplaceCountry?: string,
616
birthplaceState?: string,

web/src/lib/utils/formatBrowser.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
import type { IBrowser } from "ua-parser-js";
22

3+
/**
4+
* Given a browser from `UAParser()`, return the browser name
5+
* or "this browser" if unknown.
6+
*
7+
* Use with `UAParser(navigator.userAgent).browser` from "ua-parser-js".
8+
*
9+
* @example
10+
* formatBrowser({ name: "Chrome" })
11+
* // "Chrome"
12+
* formatBrowser(null)
13+
* // "this browser"
14+
*/
315
export function formatBrowser(browser: Partial<IBrowser> | null) {
416
return browser?.name || "this browser";
517
}

web/src/lib/utils/formatCleanUrl.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/**
2-
* Strips protocol, www prefix, and trailing slash from a URL for display.
3-
* e.g. "https://www.masstpc.org/" -> "masstpc.org"
2+
* Given a URL, return the URL without protocol, "www", or trailing slash.
3+
*
4+
* @example
5+
* formatCleanUrl("https://www.masstpc.org/")
6+
* // "masstpc.org"
47
*/
58
export function formatCleanUrl(url: string): string {
69
return url.replace(/^https?:\/\/(www\.)?/, "").replace(/\/$/, "");

0 commit comments

Comments
 (0)