diff --git a/src/components/Media/ImageMedia/index.tsx b/src/components/Media/ImageMedia/index.tsx index d8222d2..94edf15 100644 --- a/src/components/Media/ImageMedia/index.tsx +++ b/src/components/Media/ImageMedia/index.tsx @@ -4,7 +4,7 @@ import type { FunctionComponent } from "react"; import NextImage from "next/image"; import type { StaticImageData } from "next/image"; import { cssVariables } from "~/cssVariables"; -import { getClientSideURL } from "~/utilities/get-url"; +import { getMediaUrl } from "~/utilities/get-media-url"; import { cn } from "~/utilities/ui"; import type { Props as MediaProps } from "../types"; @@ -46,7 +46,7 @@ export const ImageMedia: FunctionComponent = (props) => { const cacheTag = resource.updatedAt; - src = `${getClientSideURL()}${url}?${cacheTag}`; + src = getMediaUrl(url, cacheTag); } const loading = loadingFromProps || (!priority ? "lazy" : undefined); diff --git a/src/components/Media/VideoMedia/index.tsx b/src/components/Media/VideoMedia/index.tsx index 32ed28d..325399d 100644 --- a/src/components/Media/VideoMedia/index.tsx +++ b/src/components/Media/VideoMedia/index.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef } from "react"; import type { FunctionComponent } from "react"; -import { getClientSideURL } from "~/utilities/get-url"; +import { getMediaUrl } from "~/utilities/get-media-url"; import { cn } from "~/utilities/ui"; import type { Props as MediaProps } from "../types"; @@ -36,7 +36,7 @@ export const VideoMedia: FunctionComponent = (props) => { playsInline ref={videoRef} > - + ); } diff --git a/src/utilities/get-media-url/index.ts b/src/utilities/get-media-url/index.ts new file mode 100644 index 0000000..dfdbfda --- /dev/null +++ b/src/utilities/get-media-url/index.ts @@ -0,0 +1,23 @@ +import { getClientSideURL } from "~/utilities/get-url/"; + +/** + * Processes media resource URL to ensure proper formatting + * @param url The original URL from the resource + * @param cacheTag Optional cache tag to append to the URL + * @returns Properly formatted URL with cache tag if provided + */ +export const getMediaUrl = ( + url: string | null | undefined, + cacheTag?: string | null, +): string => { + if (!url) return ""; + + // Check if URL already has http/https protocol + if (url.startsWith("http://") || url.startsWith("https://")) { + return cacheTag ? `${url}?${cacheTag}` : url; + } + + // Otherwise prepend client-side URL + const baseUrl = getClientSideURL(); + return cacheTag ? `${baseUrl}${url}?${cacheTag}` : `${baseUrl}${url}`; +}; diff --git a/src/utilities/get-media-url/test.ts b/src/utilities/get-media-url/test.ts new file mode 100644 index 0000000..3dfb7d1 --- /dev/null +++ b/src/utilities/get-media-url/test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from "@jest/globals"; +import { getMediaUrl } from "."; + +describe("utilities", () => { + describe("getMediaUrl", () => { + it("use no url", () => { + // @ts-expect-error cope with no arguments + expect(getMediaUrl()).toBe(""); + }); + + it("use full url", () => { + expect(getMediaUrl("http://localhost:3000")).toBe( + "http://localhost:3000", + ); + }); + + it("use full url with cacheTag", () => { + expect(getMediaUrl("http://localhost:3000", "tag=tag")).toBe( + "http://localhost:3000?tag=tag", + ); + }); + + it("use client browser plus endpoint", () => { + Object.defineProperty(window, "location", { + value: new URL("http://localhost:3000"), + }); + + expect(getMediaUrl("/foo")).toBe("http://localhost:3000/foo"); + }); + + it("use client browser plus endpoint with cacheTage", () => { + Object.defineProperty(window, "location", { + value: new URL("http://localhost:3000"), + }); + + expect(getMediaUrl("/foo", "tag=tag")).toBe( + "http://localhost:3000/foo?tag=tag", + ); + }); + }); +});